mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-15 15:49:36 +02:00
Merge pull request #923 from Paul-Licameli/Review-of-dithering
Review of dithering
This commit is contained in:
commit
428506ea2f
@ -3622,11 +3622,9 @@ static void DoSoftwarePlaythrough(const void *inputBuffer,
|
|||||||
{
|
{
|
||||||
for (unsigned int i=0; i < inputChannels; i++) {
|
for (unsigned int i=0; i < inputChannels; i++) {
|
||||||
samplePtr inputPtr = ((samplePtr)inputBuffer) + (i * SAMPLE_SIZE(inputFormat));
|
samplePtr inputPtr = ((samplePtr)inputBuffer) + (i * SAMPLE_SIZE(inputFormat));
|
||||||
samplePtr outputPtr = ((samplePtr)outputBuffer) + (i * SAMPLE_SIZE(floatSample));
|
|
||||||
|
|
||||||
CopySamples(inputPtr, inputFormat,
|
SamplesToFloats(inputPtr, inputFormat,
|
||||||
(samplePtr)outputPtr, floatSample,
|
outputBuffer + i, len, inputChannels, 2);
|
||||||
len, true, inputChannels, 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// One mono input channel goes to both output channels...
|
// One mono input channel goes to both output channels...
|
||||||
@ -4411,9 +4409,8 @@ int AudioIoCallback::AudioCallback(const void *inputBuffer, void *outputBuffer,
|
|||||||
inputSamples = (float *) inputBuffer;
|
inputSamples = (float *) inputBuffer;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
CopySamples((samplePtr)inputBuffer, mCaptureFormat,
|
SamplesToFloats(reinterpret_cast<constSamplePtr>(inputBuffer),
|
||||||
(samplePtr)tempFloats, floatSample,
|
mCaptureFormat, tempFloats, framesPerBuffer * numCaptureChannels);
|
||||||
framesPerBuffer * numCaptureChannels);
|
|
||||||
inputSamples = tempFloats;
|
inputSamples = tempFloats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -602,7 +602,7 @@ void FrequencyPlotDialog::GetAudio()
|
|||||||
mDataLen = dataLen.as_size_t();
|
mDataLen = dataLen.as_size_t();
|
||||||
mData = Floats{ mDataLen };
|
mData = Floats{ mDataLen };
|
||||||
// Don't allow throw for bad reads
|
// Don't allow throw for bad reads
|
||||||
track->Get((samplePtr)mData.get(), floatSample, start, mDataLen,
|
track->GetFloats(mData.get(), start, mDataLen,
|
||||||
fillZero, false);
|
fillZero, false);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -617,7 +617,7 @@ void FrequencyPlotDialog::GetAudio()
|
|||||||
auto start = track->TimeToLongSamples(selectedRegion.t0());
|
auto start = track->TimeToLongSamples(selectedRegion.t0());
|
||||||
Floats buffer2{ mDataLen };
|
Floats buffer2{ mDataLen };
|
||||||
// Again, stop exceptions
|
// Again, stop exceptions
|
||||||
track->Get((samplePtr)buffer2.get(), floatSample, start, mDataLen,
|
track->GetFloats(buffer2.get(), start, mDataLen,
|
||||||
fillZero, false);
|
fillZero, false);
|
||||||
for (size_t i = 0; i < mDataLen; i++)
|
for (size_t i = 0; i < mDataLen; i++)
|
||||||
mData[i] += buffer2[i];
|
mData[i] += buffer2[i];
|
||||||
|
13
src/Mix.cpp
13
src/Mix.cpp
@ -460,7 +460,8 @@ size_t Mixer::MixVariableRates(int *channelFlags, WaveTrackCache &cache,
|
|||||||
// Nothing to do if past end of play interval
|
// Nothing to do if past end of play interval
|
||||||
if (getLen > 0) {
|
if (getLen > 0) {
|
||||||
if (backwards) {
|
if (backwards) {
|
||||||
auto results = cache.Get(floatSample, *pos - (getLen - 1), getLen, mMayThrow);
|
auto results =
|
||||||
|
cache.GetFloats(*pos - (getLen - 1), getLen, mMayThrow);
|
||||||
if (results)
|
if (results)
|
||||||
memcpy(&queue[*queueLen], results, sizeof(float) * getLen);
|
memcpy(&queue[*queueLen], results, sizeof(float) * getLen);
|
||||||
else
|
else
|
||||||
@ -472,7 +473,7 @@ size_t Mixer::MixVariableRates(int *channelFlags, WaveTrackCache &cache,
|
|||||||
*pos -= getLen;
|
*pos -= getLen;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
auto results = cache.Get(floatSample, *pos, getLen, mMayThrow);
|
auto results = cache.GetFloats(*pos, getLen, mMayThrow);
|
||||||
if (results)
|
if (results)
|
||||||
memcpy(&queue[*queueLen], results, sizeof(float) * getLen);
|
memcpy(&queue[*queueLen], results, sizeof(float) * getLen);
|
||||||
else
|
else
|
||||||
@ -589,7 +590,7 @@ size_t Mixer::MixSameRate(int *channelFlags, WaveTrackCache &cache,
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (backwards) {
|
if (backwards) {
|
||||||
auto results = cache.Get(floatSample, *pos - (slen - 1), slen, mMayThrow);
|
auto results = cache.GetFloats(*pos - (slen - 1), slen, mMayThrow);
|
||||||
if (results)
|
if (results)
|
||||||
memcpy(mFloatBuffer.get(), results, sizeof(float) * slen);
|
memcpy(mFloatBuffer.get(), results, sizeof(float) * slen);
|
||||||
else
|
else
|
||||||
@ -602,7 +603,7 @@ size_t Mixer::MixSameRate(int *channelFlags, WaveTrackCache &cache,
|
|||||||
*pos -= slen;
|
*pos -= slen;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
auto results = cache.Get(floatSample, *pos, slen, mMayThrow);
|
auto results = cache.GetFloats(*pos, slen, mMayThrow);
|
||||||
if (results)
|
if (results)
|
||||||
memcpy(mFloatBuffer.get(), results, sizeof(float) * slen);
|
memcpy(mFloatBuffer.get(), results, sizeof(float) * slen);
|
||||||
else
|
else
|
||||||
@ -691,7 +692,7 @@ size_t Mixer::Process(size_t maxToProcess)
|
|||||||
mBuffer[0].ptr() + (c * SAMPLE_SIZE(mFormat)),
|
mBuffer[0].ptr() + (c * SAMPLE_SIZE(mFormat)),
|
||||||
mFormat,
|
mFormat,
|
||||||
maxOut,
|
maxOut,
|
||||||
mHighQuality,
|
mHighQuality ? gHighQualityDither : gLowQualityDither,
|
||||||
mNumChannels,
|
mNumChannels,
|
||||||
mNumChannels);
|
mNumChannels);
|
||||||
}
|
}
|
||||||
@ -703,7 +704,7 @@ size_t Mixer::Process(size_t maxToProcess)
|
|||||||
mBuffer[c].ptr(),
|
mBuffer[c].ptr(),
|
||||||
mFormat,
|
mFormat,
|
||||||
maxOut,
|
maxOut,
|
||||||
mHighQuality);
|
mHighQuality ? gHighQualityDither : gLowQualityDither);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// MB: this doesn't take warping into account, replaced with code based on mSamplePos
|
// MB: this doesn't take warping into account, replaced with code based on mSamplePos
|
||||||
|
@ -610,8 +610,8 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
|
|||||||
Floats tempFloatsArray{ nFrames };
|
Floats tempFloatsArray{ nFrames };
|
||||||
decltype(tempFloatsArray) meterFloatsArray;
|
decltype(tempFloatsArray) meterFloatsArray;
|
||||||
// Don't throw on read error in this drawing update routine
|
// Don't throw on read error in this drawing update routine
|
||||||
bool bSuccess = pTrack->Get((samplePtr)tempFloatsArray.get(),
|
bool bSuccess = pTrack->GetFloats(tempFloatsArray.get(),
|
||||||
floatSample, startSample, nFrames, fillZero, false);
|
startSample, nFrames, fillZero, false);
|
||||||
if (bSuccess)
|
if (bSuccess)
|
||||||
{
|
{
|
||||||
// We always pass a stereo sample array to the meter, as it shows 2 channels.
|
// We always pass a stereo sample array to the meter, as it shows 2 channels.
|
||||||
@ -625,8 +625,8 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
|
|||||||
|
|
||||||
if (GetRight())
|
if (GetRight())
|
||||||
// Again, don't throw
|
// Again, don't throw
|
||||||
bSuccess = GetRight()->Get((samplePtr)tempFloatsArray.get(),
|
bSuccess = GetRight()->GetFloats(tempFloatsArray.get(),
|
||||||
floatSample, startSample, nFrames, fillZero, false);
|
startSample, nFrames, fillZero, false);
|
||||||
|
|
||||||
if (bSuccess)
|
if (bSuccess)
|
||||||
// Interleave right channel, or duplicate same signal for "right" channel in mono case.
|
// Interleave right channel, or duplicate same signal for "right" channel in mono case.
|
||||||
|
@ -85,7 +85,7 @@ size_t RingBuffer::Put(samplePtr buffer, sampleFormat format,
|
|||||||
|
|
||||||
CopySamples(src, format,
|
CopySamples(src, format,
|
||||||
mBuffer.ptr() + pos * SAMPLE_SIZE(mFormat), mFormat,
|
mBuffer.ptr() + pos * SAMPLE_SIZE(mFormat), mFormat,
|
||||||
block);
|
block, DitherType::none);
|
||||||
|
|
||||||
src += block * SAMPLE_SIZE(format);
|
src += block * SAMPLE_SIZE(format);
|
||||||
pos = (pos + block) % mBufferSize;
|
pos = (pos + block) % mBufferSize;
|
||||||
@ -167,7 +167,7 @@ size_t RingBuffer::Get(samplePtr buffer, sampleFormat format,
|
|||||||
|
|
||||||
CopySamples(mBuffer.ptr() + start * SAMPLE_SIZE(mFormat), mFormat,
|
CopySamples(mBuffer.ptr() + start * SAMPLE_SIZE(mFormat), mFormat,
|
||||||
dest, format,
|
dest, format,
|
||||||
block);
|
block, DitherType::none);
|
||||||
|
|
||||||
dest += block * SAMPLE_SIZE(format);
|
dest += block * SAMPLE_SIZE(format);
|
||||||
start = (start + block) % mBufferSize;
|
start = (start + block) % mBufferSize;
|
||||||
|
@ -24,6 +24,7 @@ class RingBuffer {
|
|||||||
//
|
//
|
||||||
|
|
||||||
size_t AvailForPut();
|
size_t AvailForPut();
|
||||||
|
//! Does not apply dithering
|
||||||
size_t Put(samplePtr buffer, sampleFormat format, size_t samples,
|
size_t Put(samplePtr buffer, sampleFormat format, size_t samples,
|
||||||
// optional number of trailing zeroes
|
// optional number of trailing zeroes
|
||||||
size_t padding = 0);
|
size_t padding = 0);
|
||||||
@ -34,6 +35,7 @@ class RingBuffer {
|
|||||||
//
|
//
|
||||||
|
|
||||||
size_t AvailForGet();
|
size_t AvailForGet();
|
||||||
|
//! Does not apply dithering
|
||||||
size_t Get(samplePtr buffer, sampleFormat format, size_t samples);
|
size_t Get(samplePtr buffer, sampleFormat format, size_t samples);
|
||||||
size_t Discard(size_t samples);
|
size_t Discard(size_t samples);
|
||||||
|
|
||||||
|
@ -43,11 +43,10 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "Prefs.h"
|
#include "Prefs.h"
|
||||||
#include "Dither.h"
|
|
||||||
#include "Internat.h"
|
#include "Internat.h"
|
||||||
|
|
||||||
static DitherType gLowQualityDither = DitherType::none;
|
DitherType gLowQualityDither = DitherType::none;
|
||||||
static DitherType gHighQualityDither = DitherType::none;
|
DitherType gHighQualityDither = DitherType::shaped;
|
||||||
static Dither gDitherAlgorithm;
|
static Dither gDitherAlgorithm;
|
||||||
|
|
||||||
void InitDitherers()
|
void InitDitherers()
|
||||||
@ -99,25 +98,22 @@ void ReverseSamples(samplePtr dst, sampleFormat format,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CopySamples(constSamplePtr src, sampleFormat srcFormat,
|
void SamplesToFloats(constSamplePtr src, sampleFormat srcFormat,
|
||||||
samplePtr dst, sampleFormat dstFormat,
|
float *dst, size_t len, size_t srcStride, size_t dstStride)
|
||||||
unsigned int len,
|
|
||||||
bool highQuality, /* = true */
|
|
||||||
unsigned int srcStride /* = 1 */,
|
|
||||||
unsigned int dstStride /* = 1 */)
|
|
||||||
{
|
{
|
||||||
gDitherAlgorithm.Apply(
|
CopySamples( src, srcFormat,
|
||||||
highQuality ? gHighQualityDither : gLowQualityDither,
|
reinterpret_cast<samplePtr>(dst), floatSample, len,
|
||||||
src, srcFormat, dst, dstFormat, len, srcStride, dstStride);
|
DitherType::none,
|
||||||
|
srcStride, dstStride);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CopySamplesNoDither(samplePtr src, sampleFormat srcFormat,
|
void CopySamples(constSamplePtr src, sampleFormat srcFormat,
|
||||||
samplePtr dst, sampleFormat dstFormat,
|
samplePtr dst, sampleFormat dstFormat, size_t len,
|
||||||
unsigned int len,
|
DitherType ditherType, /* = gHighQualityDither */
|
||||||
unsigned int srcStride /* = 1 */,
|
unsigned int srcStride /* = 1 */,
|
||||||
unsigned int dstStride /* = 1 */)
|
unsigned int dstStride /* = 1 */)
|
||||||
{
|
{
|
||||||
gDitherAlgorithm.Apply(
|
gDitherAlgorithm.Apply(
|
||||||
DitherType::none,
|
ditherType,
|
||||||
src, srcFormat, dst, dstFormat, len, srcStride, dstStride);
|
src, srcFormat, dst, dstFormat, len, srcStride, dstStride);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Audacity: A Digital Audio Editor
|
Audacity: A Digital Audio Editor
|
||||||
|
|
||||||
SampleFormat.h
|
@file SampleFormat.h
|
||||||
|
|
||||||
Dominic Mazzoni
|
Dominic Mazzoni
|
||||||
|
|
||||||
@ -17,11 +17,15 @@
|
|||||||
#include <wx/defs.h>
|
#include <wx/defs.h>
|
||||||
|
|
||||||
#include "audacity/Types.h"
|
#include "audacity/Types.h"
|
||||||
|
#include "Dither.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// Definitions / Meta-Information
|
// Definitions / Meta-Information
|
||||||
//
|
//
|
||||||
|
|
||||||
|
//! These global variables are assigned at application startup or after change of preferences.
|
||||||
|
extern AUDACITY_DLL_API DitherType gLowQualityDither, gHighQualityDither;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// Moved to audacity/types.h
|
// Moved to audacity/types.h
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -125,18 +129,29 @@ private:
|
|||||||
//
|
//
|
||||||
|
|
||||||
AUDACITY_DLL_API
|
AUDACITY_DLL_API
|
||||||
void CopySamples(constSamplePtr src, sampleFormat srcFormat,
|
//! Copy samples from any format into the widest format, which is 32 bit float, with no dithering
|
||||||
samplePtr dst, sampleFormat dstFormat,
|
/*!
|
||||||
unsigned int len, bool highQuality=true,
|
@param src address of source samples
|
||||||
unsigned int srcStride=1,
|
@param srcFormat format of source samples, determines sizeof each one
|
||||||
unsigned int dstStride=1);
|
@param dst address of floating-point numbers
|
||||||
|
@param len count of samples to copy
|
||||||
|
@param srcStride how many samples to advance src after copying each one
|
||||||
|
@param dstString how many samples to advance dst after copying each one
|
||||||
|
*/
|
||||||
|
void SamplesToFloats(constSamplePtr src, sampleFormat srcFormat,
|
||||||
|
float *dst, size_t len, size_t srcStride = 1, size_t dstStride = 1);
|
||||||
|
|
||||||
AUDACITY_DLL_API
|
AUDACITY_DLL_API
|
||||||
void CopySamplesNoDither(samplePtr src, sampleFormat srcFormat,
|
//! Copy samples from any format to any other format; apply dithering only if narrowing the format
|
||||||
samplePtr dst, sampleFormat dstFormat,
|
/*!
|
||||||
unsigned int len,
|
@copydetails SamplesToFloats()
|
||||||
unsigned int srcStride=1,
|
@param dstFormat format of destination samples, determines sizeof each one
|
||||||
unsigned int dstStride=1);
|
@param ditherType choice of dithering algorithm to use if narrowing the format
|
||||||
|
*/
|
||||||
|
void CopySamples(constSamplePtr src, sampleFormat srcFormat,
|
||||||
|
samplePtr dst, sampleFormat dstFormat, size_t len,
|
||||||
|
DitherType ditherType = gHighQualityDither, //!< default is loaded from a global variable
|
||||||
|
unsigned int srcStride=1, unsigned int dstStride=1);
|
||||||
|
|
||||||
AUDACITY_DLL_API
|
AUDACITY_DLL_API
|
||||||
void ClearSamples(samplePtr buffer, sampleFormat format,
|
void ClearSamples(samplePtr buffer, sampleFormat format,
|
||||||
|
@ -593,6 +593,42 @@ size_t SqliteSampleBlock::GetBlob(void *dest,
|
|||||||
srcoffset += 0;
|
srcoffset += 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Will dithering happen in CopySamples? Answering this as of 3.0.3 by
|
||||||
|
examining all uses.
|
||||||
|
|
||||||
|
As this function is called from GetSummary, no, because destination format
|
||||||
|
is float.
|
||||||
|
|
||||||
|
There is only one other call to this function, in DoGetSamples. At one
|
||||||
|
call to that function, in DoGetMinMaxRMS, again format is float always.
|
||||||
|
|
||||||
|
There is only one other call to DoGetSamples, in SampleBlock::GetSamples().
|
||||||
|
In one call to that function, in WaveformView.cpp, again format is float.
|
||||||
|
|
||||||
|
That leaves two calls in Sequence.cpp. One of those can be proved to be
|
||||||
|
used only in copy and paste operations, always supplying the same sample
|
||||||
|
format as the samples were stored in, therefore no dither.
|
||||||
|
|
||||||
|
That leaves uses of Sequence::Read(). There are uses of Read() in internal
|
||||||
|
operations also easily shown to use only the saved format, and
|
||||||
|
GetWaveDisplay() always reads as float.
|
||||||
|
|
||||||
|
The remaining use of Sequence::Read() is in Sequence::Get(). That is used
|
||||||
|
by WaveClip::Resample(), always fetching float. It is also used in
|
||||||
|
WaveClip::GetSamples().
|
||||||
|
|
||||||
|
There is only one use of that function not always fetching float, in
|
||||||
|
WaveTrack::Get().
|
||||||
|
|
||||||
|
It can be shown that the only paths to WaveTrack::Get() not specifying
|
||||||
|
floatSample are in Benchmark, which is only a diagnostic test, and there
|
||||||
|
the sample format is the same as what the track was constructed with.
|
||||||
|
|
||||||
|
Therefore, no dithering even there!
|
||||||
|
*/
|
||||||
|
wxASSERT(destformat == floatSample || destformat == srcformat);
|
||||||
|
|
||||||
CopySamples(src + srcoffset,
|
CopySamples(src + srcoffset,
|
||||||
srcformat,
|
srcformat,
|
||||||
(samplePtr) dest,
|
(samplePtr) dest,
|
||||||
@ -806,11 +842,8 @@ void SqliteSampleBlock::CalcSummary(Sizes sizes)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
samplebuffer.reinit((unsigned) mSampleCount);
|
samplebuffer.reinit((unsigned) mSampleCount);
|
||||||
CopySamples(mSamples.get(),
|
SamplesToFloats(mSamples.get(), mSampleFormat,
|
||||||
mSampleFormat,
|
samplebuffer.get(), mSampleCount);
|
||||||
(samplePtr) samplebuffer.get(),
|
|
||||||
floatSample,
|
|
||||||
mSampleCount);
|
|
||||||
samples = samplebuffer.get();
|
samples = samplebuffer.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ sampleCount VoiceKey::OnForward (
|
|||||||
//To speed things up, create a local buffer to store things in, to avoid the costly t.Get();
|
//To speed things up, create a local buffer to store things in, to avoid the costly t.Get();
|
||||||
//Only go through the first SignalWindowSizeInt samples, and choose the first that trips the key.
|
//Only go through the first SignalWindowSizeInt samples, and choose the first that trips the key.
|
||||||
Floats buffer{ remaining };
|
Floats buffer{ remaining };
|
||||||
t.Get((samplePtr)buffer.get(), floatSample,
|
t.GetFloats(buffer.get(),
|
||||||
lastsubthresholdsample, remaining);
|
lastsubthresholdsample, remaining);
|
||||||
|
|
||||||
|
|
||||||
@ -299,7 +299,7 @@ sampleCount VoiceKey::OnBackward (
|
|||||||
//To speed things up, create a local buffer to store things in, to avoid the costly t.Get();
|
//To speed things up, create a local buffer to store things in, to avoid the costly t.Get();
|
||||||
//Only go through the first mSilentWindowSizeInt samples, and choose the first that trips the key.
|
//Only go through the first mSilentWindowSizeInt samples, and choose the first that trips the key.
|
||||||
Floats buffer{ remaining };
|
Floats buffer{ remaining };
|
||||||
t.Get((samplePtr)buffer.get(), floatSample,
|
t.GetFloats(buffer.get(),
|
||||||
lastsubthresholdsample - remaining, remaining);
|
lastsubthresholdsample - remaining, remaining);
|
||||||
|
|
||||||
//Initialize these trend markers atrend and ztrend. They keep track of the
|
//Initialize these trend markers atrend and ztrend. They keep track of the
|
||||||
@ -442,7 +442,7 @@ sampleCount VoiceKey::OffForward (
|
|||||||
//To speed things up, create a local buffer to store things in, to avoid the costly t.Get();
|
//To speed things up, create a local buffer to store things in, to avoid the costly t.Get();
|
||||||
//Only go through the first SilentWindowSizeInt samples, and choose the first that trips the key.
|
//Only go through the first SilentWindowSizeInt samples, and choose the first that trips the key.
|
||||||
Floats buffer{ remaining };
|
Floats buffer{ remaining };
|
||||||
t.Get((samplePtr)buffer.get(), floatSample,
|
t.GetFloats(buffer.get(),
|
||||||
lastsubthresholdsample, remaining);
|
lastsubthresholdsample, remaining);
|
||||||
|
|
||||||
//Initialize these trend markers atrend and ztrend. They keep track of the
|
//Initialize these trend markers atrend and ztrend. They keep track of the
|
||||||
@ -579,7 +579,7 @@ sampleCount VoiceKey::OffBackward (
|
|||||||
//To speed things up, create a local buffer to store things in, to avoid the costly t.Get();
|
//To speed things up, create a local buffer to store things in, to avoid the costly t.Get();
|
||||||
//Only go through the first SilentWindowSizeInt samples, and choose the first that trips the key.
|
//Only go through the first SilentWindowSizeInt samples, and choose the first that trips the key.
|
||||||
Floats buffer{ remaining };
|
Floats buffer{ remaining };
|
||||||
t.Get((samplePtr)buffer.get(), floatSample,
|
t.GetFloats(buffer.get(),
|
||||||
lastsubthresholdsample - remaining, remaining);
|
lastsubthresholdsample - remaining, remaining);
|
||||||
|
|
||||||
//Initialize these trend markers atrend and ztrend. They keep track of the
|
//Initialize these trend markers atrend and ztrend. They keep track of the
|
||||||
@ -870,7 +870,7 @@ double VoiceKey::TestEnergy (
|
|||||||
//Figure out how much to grab
|
//Figure out how much to grab
|
||||||
auto block = limitSampleBufferSize ( t.GetBestBlockSize(s), len );
|
auto block = limitSampleBufferSize ( t.GetBestBlockSize(s), len );
|
||||||
|
|
||||||
t.Get((samplePtr)buffer.get(), floatSample, s,block); //grab the block;
|
t.GetFloats(buffer.get(), s,block); //grab the block;
|
||||||
|
|
||||||
//Now, go through the block and calculate energy
|
//Now, go through the block and calculate energy
|
||||||
for(decltype(block) i = 0; i< block; i++)
|
for(decltype(block) i = 0; i< block; i++)
|
||||||
@ -913,7 +913,7 @@ double VoiceKey::TestSignChanges(
|
|||||||
//Figure out how much to grab
|
//Figure out how much to grab
|
||||||
auto block = limitSampleBufferSize ( t.GetBestBlockSize(s), len );
|
auto block = limitSampleBufferSize ( t.GetBestBlockSize(s), len );
|
||||||
|
|
||||||
t.Get((samplePtr)buffer.get(), floatSample, s, block); //grab the block;
|
t.GetFloats(buffer.get(), s, block); //grab the block;
|
||||||
|
|
||||||
if (len == originalLen)
|
if (len == originalLen)
|
||||||
{
|
{
|
||||||
@ -970,7 +970,7 @@ double VoiceKey::TestDirectionChanges(
|
|||||||
//Figure out how much to grab
|
//Figure out how much to grab
|
||||||
auto block = limitSampleBufferSize ( t.GetBestBlockSize(s), len );
|
auto block = limitSampleBufferSize ( t.GetBestBlockSize(s), len );
|
||||||
|
|
||||||
t.Get((samplePtr)buffer.get(), floatSample, s, block); //grab the block;
|
t.GetFloats(buffer.get(), s, block); //grab the block;
|
||||||
|
|
||||||
if (len == originalLen) {
|
if (len == originalLen) {
|
||||||
//The first time through, set stuff up special.
|
//The first time through, set stuff up special.
|
||||||
|
@ -525,9 +525,9 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0,
|
|||||||
else {
|
else {
|
||||||
b.reinit(len);
|
b.reinit(len);
|
||||||
pb = b.get();
|
pb = b.get();
|
||||||
CopySamples(mAppendBuffer.ptr() + sLeft * SAMPLE_SIZE(seqFormat),
|
SamplesToFloats(
|
||||||
seqFormat,
|
mAppendBuffer.ptr() + sLeft * SAMPLE_SIZE(seqFormat),
|
||||||
(samplePtr)pb, floatSample, len);
|
seqFormat, pb, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
float theMax, theMin, sumsq;
|
float theMax, theMin, sumsq;
|
||||||
@ -707,8 +707,8 @@ bool SpecCache::CalculateOneSpectrum
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (myLen > 0) {
|
if (myLen > 0) {
|
||||||
useBuffer = (float*)(waveTrackCache.Get(
|
useBuffer = (float*)(waveTrackCache.GetFloats(
|
||||||
floatSample, sampleCount(
|
sampleCount(
|
||||||
floor(0.5 + from.as_double() + offset * rate)
|
floor(0.5 + from.as_double() + offset * rate)
|
||||||
),
|
),
|
||||||
myLen,
|
myLen,
|
||||||
@ -1248,7 +1248,7 @@ bool WaveClip::Append(constSamplePtr buffer, sampleFormat format,
|
|||||||
mAppendBuffer.ptr() + mAppendBufferLen * SAMPLE_SIZE(seqFormat),
|
mAppendBuffer.ptr() + mAppendBufferLen * SAMPLE_SIZE(seqFormat),
|
||||||
seqFormat,
|
seqFormat,
|
||||||
toCopy,
|
toCopy,
|
||||||
true, // high quality
|
gHighQualityDither,
|
||||||
stride);
|
stride);
|
||||||
|
|
||||||
mAppendBufferLen += toCopy;
|
mAppendBufferLen += toCopy;
|
||||||
|
@ -2542,9 +2542,10 @@ void WaveTrackCache::SetTrack(const std::shared_ptr<const WaveTrack> &pTrack)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constSamplePtr WaveTrackCache::Get(sampleFormat format,
|
const float *WaveTrackCache::GetFloats(
|
||||||
sampleCount start, size_t len, bool mayThrow)
|
sampleCount start, size_t len, bool mayThrow)
|
||||||
{
|
{
|
||||||
|
constexpr auto format = floatSample;
|
||||||
if (format == floatSample && len > 0) {
|
if (format == floatSample && len > 0) {
|
||||||
const auto end = start + len;
|
const auto end = start + len;
|
||||||
|
|
||||||
@ -2593,10 +2594,10 @@ constSamplePtr WaveTrackCache::Get(sampleFormat format,
|
|||||||
if (start0 >= 0) {
|
if (start0 >= 0) {
|
||||||
const auto len0 = mPTrack->GetBestBlockSize(start0);
|
const auto len0 = mPTrack->GetBestBlockSize(start0);
|
||||||
wxASSERT(len0 <= mBufferSize);
|
wxASSERT(len0 <= mBufferSize);
|
||||||
if (!mPTrack->Get(
|
if (!mPTrack->GetFloats(
|
||||||
samplePtr(mBuffers[0].data.get()), floatSample, start0, len0,
|
mBuffers[0].data.get(), start0, len0,
|
||||||
fillZero, mayThrow))
|
fillZero, mayThrow))
|
||||||
return 0;
|
return nullptr;
|
||||||
mBuffers[0].start = start0;
|
mBuffers[0].start = start0;
|
||||||
mBuffers[0].len = len0;
|
mBuffers[0].len = len0;
|
||||||
if (!fillSecond &&
|
if (!fillSecond &&
|
||||||
@ -2621,8 +2622,8 @@ constSamplePtr WaveTrackCache::Get(sampleFormat format,
|
|||||||
if (start1 == end0) {
|
if (start1 == end0) {
|
||||||
const auto len1 = mPTrack->GetBestBlockSize(start1);
|
const auto len1 = mPTrack->GetBestBlockSize(start1);
|
||||||
wxASSERT(len1 <= mBufferSize);
|
wxASSERT(len1 <= mBufferSize);
|
||||||
if (!mPTrack->Get(samplePtr(mBuffers[1].data.get()), floatSample, start1, len1, fillZero, mayThrow))
|
if (!mPTrack->GetFloats(mBuffers[1].data.get(), start1, len1, fillZero, mayThrow))
|
||||||
return 0;
|
return nullptr;
|
||||||
mBuffers[1].start = start1;
|
mBuffers[1].start = start1;
|
||||||
mBuffers[1].len = len1;
|
mBuffers[1].len = len1;
|
||||||
mNValidBuffers = 2;
|
mNValidBuffers = 2;
|
||||||
@ -2631,7 +2632,7 @@ constSamplePtr WaveTrackCache::Get(sampleFormat format,
|
|||||||
}
|
}
|
||||||
wxASSERT(mNValidBuffers < 2 || mBuffers[0].end() == mBuffers[1].start);
|
wxASSERT(mNValidBuffers < 2 || mBuffers[0].end() == mBuffers[1].start);
|
||||||
|
|
||||||
samplePtr buffer = 0;
|
samplePtr buffer = nullptr; // will point into mOverlapBuffer
|
||||||
auto remaining = len;
|
auto remaining = len;
|
||||||
|
|
||||||
// Possibly get an initial portion that is uncached
|
// Possibly get an initial portion that is uncached
|
||||||
@ -2646,9 +2647,11 @@ constSamplePtr WaveTrackCache::Get(sampleFormat format,
|
|||||||
mOverlapBuffer.Resize(len, format);
|
mOverlapBuffer.Resize(len, format);
|
||||||
// initLen is not more than len:
|
// initLen is not more than len:
|
||||||
auto sinitLen = initLen.as_size_t();
|
auto sinitLen = initLen.as_size_t();
|
||||||
if (!mPTrack->Get(mOverlapBuffer.ptr(), format, start, sinitLen,
|
if (!mPTrack->GetFloats(
|
||||||
fillZero, mayThrow))
|
// See comment below about casting
|
||||||
return 0;
|
reinterpret_cast<float *>(mOverlapBuffer.ptr()),
|
||||||
|
start, sinitLen, fillZero, mayThrow))
|
||||||
|
return nullptr;
|
||||||
wxASSERT( sinitLen <= remaining );
|
wxASSERT( sinitLen <= remaining );
|
||||||
remaining -= sinitLen;
|
remaining -= sinitLen;
|
||||||
start += initLen;
|
start += initLen;
|
||||||
@ -2669,12 +2672,12 @@ constSamplePtr WaveTrackCache::Get(sampleFormat format,
|
|||||||
// All is contiguous already. We can completely avoid copying
|
// All is contiguous already. We can completely avoid copying
|
||||||
// leni is nonnegative, therefore start falls within mBuffers[ii],
|
// leni is nonnegative, therefore start falls within mBuffers[ii],
|
||||||
// so starti is bounded between 0 and buffer length
|
// so starti is bounded between 0 and buffer length
|
||||||
return samplePtr(mBuffers[ii].data.get() + starti.as_size_t() );
|
return mBuffers[ii].data.get() + starti.as_size_t() ;
|
||||||
}
|
}
|
||||||
else if (leni > 0) {
|
else if (leni > 0) {
|
||||||
// leni is nonnegative, therefore start falls within mBuffers[ii]
|
// leni is nonnegative, therefore start falls within mBuffers[ii]
|
||||||
// But we can't satisfy all from one buffer, so copy
|
// But we can't satisfy all from one buffer, so copy
|
||||||
if (buffer == 0) {
|
if (!buffer) {
|
||||||
mOverlapBuffer.Resize(len, format);
|
mOverlapBuffer.Resize(len, format);
|
||||||
buffer = mOverlapBuffer.ptr();
|
buffer = mOverlapBuffer.ptr();
|
||||||
}
|
}
|
||||||
@ -2692,23 +2695,31 @@ constSamplePtr WaveTrackCache::Get(sampleFormat format,
|
|||||||
if (remaining > 0) {
|
if (remaining > 0) {
|
||||||
// Very big request!
|
// Very big request!
|
||||||
// Fall back to direct fetch
|
// Fall back to direct fetch
|
||||||
if (buffer == 0) {
|
if (!buffer) {
|
||||||
mOverlapBuffer.Resize(len, format);
|
mOverlapBuffer.Resize(len, format);
|
||||||
buffer = mOverlapBuffer.ptr();
|
buffer = mOverlapBuffer.ptr();
|
||||||
}
|
}
|
||||||
if (!mPTrack->Get(buffer, format, start, remaining, fillZero, mayThrow))
|
// See comment below about casting
|
||||||
|
if (!mPTrack->GetFloats( reinterpret_cast<float*>(buffer),
|
||||||
|
start, remaining, fillZero, mayThrow))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mOverlapBuffer.ptr();
|
// Overlap buffer was meant for the more general support of sample formats
|
||||||
|
// besides float, which explains the cast
|
||||||
|
return reinterpret_cast<const float*>(mOverlapBuffer.ptr());
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
#if 0
|
||||||
// Cache works only for float format.
|
// Cache works only for float format.
|
||||||
mOverlapBuffer.Resize(len, format);
|
mOverlapBuffer.Resize(len, format);
|
||||||
if (mPTrack->Get(mOverlapBuffer.ptr(), format, start, len, fillZero, mayThrow))
|
if (mPTrack->Get(mOverlapBuffer.ptr(), format, start, len, fillZero, mayThrow))
|
||||||
return mOverlapBuffer.ptr();
|
return mOverlapBuffer.ptr();
|
||||||
else
|
#else
|
||||||
return 0;
|
// No longer handling other than float format. Therefore len is 0.
|
||||||
|
#endif
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaveTrackCache::Free()
|
void WaveTrackCache::Free()
|
||||||
|
@ -246,6 +246,31 @@ private:
|
|||||||
/// same value for "start" in both calls to "Set" and "Get" it is
|
/// same value for "start" in both calls to "Set" and "Get" it is
|
||||||
/// guaranteed that the same samples are affected.
|
/// guaranteed that the same samples are affected.
|
||||||
///
|
///
|
||||||
|
|
||||||
|
//! Retrieve samples from a track in floating-point format, regardless of the storage format
|
||||||
|
/*!
|
||||||
|
@param buffer receives the samples
|
||||||
|
@param start starting sample, relative to absolute time zero (not to the track's offset value)
|
||||||
|
@param len how many samples to get. buffer is assumed sufficiently large
|
||||||
|
@param fill how to assign values for sample positions between clips
|
||||||
|
@param mayThrow if false, fill buffer with zeros when there is failure to retrieve samples; else throw
|
||||||
|
@param[out] pNumWithinClips Report how many samples were copied from within clips, rather
|
||||||
|
than filled according to fillFormat; but these were not necessarily one contiguous range.
|
||||||
|
*/
|
||||||
|
bool GetFloats(float *buffer, sampleCount start, size_t len,
|
||||||
|
fillFormat fill = fillZero, bool mayThrow = true,
|
||||||
|
sampleCount * pNumWithinClips = nullptr) const
|
||||||
|
{
|
||||||
|
//! Cast the pointer to pass it to Get() which handles multiple destination formats
|
||||||
|
return Get(reinterpret_cast<samplePtr>(buffer),
|
||||||
|
floatSample, start, len, fill, mayThrow, pNumWithinClips);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Retrieve samples from a track in a specified format
|
||||||
|
/*!
|
||||||
|
@copydetails WaveTrack::GetFloats()
|
||||||
|
@param format sample format of the destination buffer
|
||||||
|
*/
|
||||||
bool Get(samplePtr buffer, sampleFormat format,
|
bool Get(samplePtr buffer, sampleFormat format,
|
||||||
sampleCount start, size_t len,
|
sampleCount start, size_t len,
|
||||||
fillFormat fill = fillZero,
|
fillFormat fill = fillZero,
|
||||||
@ -254,6 +279,7 @@ private:
|
|||||||
// filled according to fillFormat; but these were not necessarily one
|
// filled according to fillFormat; but these were not necessarily one
|
||||||
// contiguous range.
|
// contiguous range.
|
||||||
sampleCount * pNumWithinClips = nullptr) const;
|
sampleCount * pNumWithinClips = nullptr) const;
|
||||||
|
|
||||||
void Set(constSamplePtr buffer, sampleFormat format,
|
void Set(constSamplePtr buffer, sampleFormat format,
|
||||||
sampleCount start, size_t len);
|
sampleCount start, size_t len);
|
||||||
|
|
||||||
@ -592,10 +618,9 @@ private:
|
|||||||
std::unique_ptr<WaveformSettings> mpWaveformSettings;
|
std::unique_ptr<WaveformSettings> mpWaveformSettings;
|
||||||
};
|
};
|
||||||
|
|
||||||
// This is meant to be a short-lived object, during whose lifetime,
|
//! A short-lived object, during whose lifetime, the contents of the WaveTrack are assumed not to change.
|
||||||
// the contents of the WaveTrack are known not to change. It can replace
|
/*! It can replace repeated calls to WaveTrack::Get() (each of which opens and closes at least one block).
|
||||||
// repeated calls to WaveTrack::Get() (each of which opens and closes at least
|
*/
|
||||||
// one block file).
|
|
||||||
class AUDACITY_DLL_API WaveTrackCache {
|
class AUDACITY_DLL_API WaveTrackCache {
|
||||||
public:
|
public:
|
||||||
WaveTrackCache()
|
WaveTrackCache()
|
||||||
@ -617,12 +642,11 @@ public:
|
|||||||
const std::shared_ptr<const WaveTrack>& GetTrack() const { return mPTrack; }
|
const std::shared_ptr<const WaveTrack>& GetTrack() const { return mPTrack; }
|
||||||
void SetTrack(const std::shared_ptr<const WaveTrack> &pTrack);
|
void SetTrack(const std::shared_ptr<const WaveTrack> &pTrack);
|
||||||
|
|
||||||
// Uses fillZero always
|
//! Retrieve samples as floats from the track or from the memory cache
|
||||||
// Returns null on failure
|
/*! Uses fillZero always
|
||||||
// Returned pointer may be invalidated if Get is called again
|
@return null on failure; this object owns the memory; may be invalidated if GetFloats() is called again
|
||||||
// Do not DELETE[] the pointer
|
*/
|
||||||
constSamplePtr Get(
|
const float *GetFloats(sampleCount start, size_t len, bool mayThrow);
|
||||||
sampleFormat format, sampleCount start, size_t len, bool mayThrow);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Free();
|
void Free();
|
||||||
|
@ -138,8 +138,8 @@ bool CompareAudioCommand::Apply(const CommandContext & context)
|
|||||||
auto block = limitSampleBufferSize(
|
auto block = limitSampleBufferSize(
|
||||||
mTrack0->GetBestBlockSize(position), s1 - position
|
mTrack0->GetBestBlockSize(position), s1 - position
|
||||||
);
|
);
|
||||||
mTrack0->Get((samplePtr)buff0.get(), floatSample, position, block);
|
mTrack0->GetFloats(buff0.get(), position, block);
|
||||||
mTrack1->Get((samplePtr)buff1.get(), floatSample, position, block);
|
mTrack1->GetFloats(buff1.get(), position, block);
|
||||||
|
|
||||||
for (decltype(block) buffPos = 0; buffPos < block; ++buffPos)
|
for (decltype(block) buffPos = 0; buffPos < block; ++buffPos)
|
||||||
{
|
{
|
||||||
|
@ -321,7 +321,7 @@ bool EffectAutoDuck::Process()
|
|||||||
{
|
{
|
||||||
const auto len = limitSampleBufferSize( kBufSize, end - pos );
|
const auto len = limitSampleBufferSize( kBufSize, end - pos );
|
||||||
|
|
||||||
mControlTrack->Get((samplePtr)buf.get(), floatSample, pos, len);
|
mControlTrack->GetFloats(buf.get(), pos, len);
|
||||||
|
|
||||||
for (auto i = pos; i < pos + len; i++)
|
for (auto i = pos; i < pos + len; i++)
|
||||||
{
|
{
|
||||||
@ -559,7 +559,7 @@ bool EffectAutoDuck::ApplyDuckFade(int trackNum, WaveTrack* t,
|
|||||||
{
|
{
|
||||||
const auto len = limitSampleBufferSize( kBufSize, end - pos );
|
const auto len = limitSampleBufferSize( kBufSize, end - pos );
|
||||||
|
|
||||||
t->Get((samplePtr)buf.get(), floatSample, pos, len);
|
t->GetFloats(buf.get(), pos, len);
|
||||||
|
|
||||||
for (auto i = pos; i < pos + len; i++)
|
for (auto i = pos; i < pos + len; i++)
|
||||||
{
|
{
|
||||||
|
@ -477,7 +477,7 @@ void EffectChangePitch::DeduceFrequencies()
|
|||||||
Floats freq{ windowSize / 2 };
|
Floats freq{ windowSize / 2 };
|
||||||
Floats freqa{ windowSize / 2, true };
|
Floats freqa{ windowSize / 2, true };
|
||||||
|
|
||||||
track->Get((samplePtr) buffer.get(), floatSample, start, analyzeSize);
|
track->GetFloats(buffer.get(), start, analyzeSize);
|
||||||
for(unsigned i = 0; i < numWindows; i++) {
|
for(unsigned i = 0; i < numWindows; i++) {
|
||||||
ComputeSpectrum(buffer.get() + i * windowSize, windowSize,
|
ComputeSpectrum(buffer.get() + i * windowSize, windowSize,
|
||||||
windowSize, rate, freq.get(), true);
|
windowSize, rate, freq.get(), true);
|
||||||
|
@ -520,7 +520,7 @@ bool EffectChangeSpeed::ProcessOne(WaveTrack * track,
|
|||||||
);
|
);
|
||||||
|
|
||||||
//Get the samples from the track and put them in the buffer
|
//Get the samples from the track and put them in the buffer
|
||||||
track->Get((samplePtr) inBuffer.get(), floatSample, samplePos, blockSize);
|
track->GetFloats(inBuffer.get(), samplePos, blockSize);
|
||||||
|
|
||||||
const auto results = resample.Process(mFactor,
|
const auto results = resample.Process(mFactor,
|
||||||
inBuffer.get(),
|
inBuffer.get(),
|
||||||
|
@ -233,7 +233,7 @@ bool EffectClickRemoval::ProcessOne(int count, WaveTrack * track, sampleCount st
|
|||||||
{
|
{
|
||||||
auto block = limitSampleBufferSize( idealBlockLen, len - s );
|
auto block = limitSampleBufferSize( idealBlockLen, len - s );
|
||||||
|
|
||||||
track->Get((samplePtr) buffer.get(), floatSample, start + s, block);
|
track->GetFloats(buffer.get(), start + s, block);
|
||||||
|
|
||||||
for (decltype(block) i = 0; i + windowSize / 2 < block; i += windowSize / 2)
|
for (decltype(block) i = 0; i + windowSize / 2 < block; i += windowSize / 2)
|
||||||
{
|
{
|
||||||
|
@ -1637,10 +1637,10 @@ bool Effect::ProcessTrack(int count,
|
|||||||
limitSampleBufferSize( mBufferSize, inputRemaining );
|
limitSampleBufferSize( mBufferSize, inputRemaining );
|
||||||
|
|
||||||
// Fill the input buffers
|
// Fill the input buffers
|
||||||
left->Get((samplePtr) inBuffer[0].get(), floatSample, inPos, inputBufferCnt);
|
left->GetFloats(inBuffer[0].get(), inPos, inputBufferCnt);
|
||||||
if (right)
|
if (right)
|
||||||
{
|
{
|
||||||
right->Get((samplePtr) inBuffer[1].get(), floatSample, inPos, inputBufferCnt);
|
right->GetFloats(inBuffer[1].get(), inPos, inputBufferCnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the input buffer positions
|
// Reset the input buffer positions
|
||||||
|
@ -1330,7 +1330,7 @@ bool EffectEqualization::ProcessOne(int count, WaveTrack * t,
|
|||||||
{
|
{
|
||||||
auto block = limitSampleBufferSize( idealBlockLen, len );
|
auto block = limitSampleBufferSize( idealBlockLen, len );
|
||||||
|
|
||||||
t->Get((samplePtr)buffer.get(), floatSample, s, block);
|
t->GetFloats(buffer.get(), s, block);
|
||||||
|
|
||||||
for(size_t i = 0; i < block; i += L) //go through block in lumps of length L
|
for(size_t i = 0; i < block; i += L) //go through block in lumps of length L
|
||||||
{
|
{
|
||||||
|
@ -198,7 +198,7 @@ bool EffectFindClipping::ProcessOne(LabelTrack * lt,
|
|||||||
|
|
||||||
block = limitSampleBufferSize( blockSize, len - s );
|
block = limitSampleBufferSize( blockSize, len - s );
|
||||||
|
|
||||||
wt->Get((samplePtr)buffer.get(), floatSample, start + s, block);
|
wt->GetFloats(buffer.get(), start + s, block);
|
||||||
ptr = buffer.get();
|
ptr = buffer.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -515,7 +515,7 @@ void EffectLoudness::LoadBufferBlock(TrackIterRange<WaveTrack> range,
|
|||||||
int idx = 0;
|
int idx = 0;
|
||||||
for(auto channel : range)
|
for(auto channel : range)
|
||||||
{
|
{
|
||||||
channel->Get((samplePtr) mTrackBuffer[idx].get(), floatSample, pos, len );
|
channel->GetFloats(mTrackBuffer[idx].get(), pos, len );
|
||||||
++idx;
|
++idx;
|
||||||
}
|
}
|
||||||
mTrackBufferLen = len;
|
mTrackBufferLen = len;
|
||||||
|
@ -1330,7 +1330,7 @@ bool EffectNoiseReduction::Worker::ProcessOne
|
|||||||
);
|
);
|
||||||
|
|
||||||
//Get the samples from the track and put them in the buffer
|
//Get the samples from the track and put them in the buffer
|
||||||
track->Get((samplePtr)&buffer[0], floatSample, samplePos, blockSize);
|
track->GetFloats(&buffer[0], samplePos, blockSize);
|
||||||
samplePos += blockSize;
|
samplePos += blockSize;
|
||||||
|
|
||||||
mInSampleCount += blockSize;
|
mInSampleCount += blockSize;
|
||||||
|
@ -435,7 +435,7 @@ bool EffectNormalize::AnalyseTrackData(const WaveTrack * track, const Translatab
|
|||||||
);
|
);
|
||||||
|
|
||||||
//Get the samples from the track and put them in the buffer
|
//Get the samples from the track and put them in the buffer
|
||||||
track->Get((samplePtr) buffer.get(), floatSample, s, block, fillZero, true, &blockSamples);
|
track->GetFloats(buffer.get(), s, block, fillZero, true, &blockSamples);
|
||||||
totalSamples += blockSamples;
|
totalSamples += blockSamples;
|
||||||
|
|
||||||
//Process the buffer.
|
//Process the buffer.
|
||||||
@ -495,7 +495,7 @@ bool EffectNormalize::ProcessOne(
|
|||||||
);
|
);
|
||||||
|
|
||||||
//Get the samples from the track and put them in the buffer
|
//Get the samples from the track and put them in the buffer
|
||||||
track->Get((samplePtr) buffer.get(), floatSample, s, block);
|
track->GetFloats(buffer.get(), s, block);
|
||||||
|
|
||||||
//Process the buffer.
|
//Process the buffer.
|
||||||
ProcessData(buffer.get(), block, offset);
|
ProcessData(buffer.get(), block, offset);
|
||||||
|
@ -359,7 +359,7 @@ bool EffectPaulstretch::ProcessOne(WaveTrack *track,double t0,double t1,int coun
|
|||||||
decltype(len) s=0;
|
decltype(len) s=0;
|
||||||
|
|
||||||
while (s < len) {
|
while (s < len) {
|
||||||
track->Get((samplePtr)bufferptr0, floatSample, start + s, nget);
|
track->GetFloats(bufferptr0, start + s, nget);
|
||||||
stretch.process(buffer0.get(), nget);
|
stretch.process(buffer0.get(), nget);
|
||||||
|
|
||||||
if (first_time) {
|
if (first_time) {
|
||||||
@ -369,7 +369,7 @@ bool EffectPaulstretch::ProcessOne(WaveTrack *track,double t0,double t1,int coun
|
|||||||
s += nget;
|
s += nget;
|
||||||
|
|
||||||
if (first_time){//blend the start of the selection
|
if (first_time){//blend the start of the selection
|
||||||
track->Get((samplePtr)fade_track_smps.get(), floatSample, start, fade_len);
|
track->GetFloats(fade_track_smps.get(), start, fade_len);
|
||||||
first_time = false;
|
first_time = false;
|
||||||
for (size_t i = 0; i < fade_len; i++){
|
for (size_t i = 0; i < fade_len; i++){
|
||||||
float fi = (float)i / (float)fade_len;
|
float fi = (float)i / (float)fade_len;
|
||||||
@ -378,7 +378,7 @@ bool EffectPaulstretch::ProcessOne(WaveTrack *track,double t0,double t1,int coun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (s >= len){//blend the end of the selection
|
if (s >= len){//blend the end of the selection
|
||||||
track->Get((samplePtr)fade_track_smps.get(), floatSample, end - fade_len, fade_len);
|
track->GetFloats(fade_track_smps.get(), end - fade_len, fade_len);
|
||||||
for (size_t i = 0; i < fade_len; i++){
|
for (size_t i = 0; i < fade_len; i++){
|
||||||
float fi = (float)i / (float)fade_len;
|
float fi = (float)i / (float)fade_len;
|
||||||
auto i2 = bufsize / 2 - 1 - i;
|
auto i2 = bufsize / 2 - 1 - i;
|
||||||
|
@ -146,7 +146,7 @@ bool EffectRepair::ProcessOne(int count, WaveTrack * track,
|
|||||||
size_t repairStart, size_t repairLen)
|
size_t repairStart, size_t repairLen)
|
||||||
{
|
{
|
||||||
Floats buffer{ len };
|
Floats buffer{ len };
|
||||||
track->Get((samplePtr) buffer.get(), floatSample, start, len);
|
track->GetFloats(buffer.get(), start, len);
|
||||||
InterpolateAudio(buffer.get(), len, repairStart, repairLen);
|
InterpolateAudio(buffer.get(), len, repairStart, repairLen);
|
||||||
track->Set((samplePtr)&buffer[repairStart], floatSample,
|
track->Set((samplePtr)&buffer[repairStart], floatSample,
|
||||||
start + repairStart, repairLen);
|
start + repairStart, repairLen);
|
||||||
|
@ -232,8 +232,8 @@ bool EffectReverse::ProcessOneClip(int count, WaveTrack *track,
|
|||||||
limitSampleBufferSize( track->GetBestBlockSize(first), len / 2 );
|
limitSampleBufferSize( track->GetBestBlockSize(first), len / 2 );
|
||||||
auto second = first + (len - block);
|
auto second = first + (len - block);
|
||||||
|
|
||||||
track->Get((samplePtr)buffer1.get(), floatSample, first, block);
|
track->GetFloats(buffer1.get(), first, block);
|
||||||
track->Get((samplePtr)buffer2.get(), floatSample, second, block);
|
track->GetFloats(buffer2.get(), second, block);
|
||||||
for (decltype(block) i = 0; i < block; i++) {
|
for (decltype(block) i = 0; i < block; i++) {
|
||||||
tmp = buffer1[i];
|
tmp = buffer1[i];
|
||||||
buffer1[i] = buffer2[block-i-1];
|
buffer1[i] = buffer2[block-i-1];
|
||||||
|
@ -99,10 +99,10 @@ long resampleCB(void *cb_data, SBSMSFrame *data)
|
|||||||
// does not seem to let us report error codes, so use this roundabout to
|
// does not seem to let us report error codes, so use this roundabout to
|
||||||
// stop the effect early.
|
// stop the effect early.
|
||||||
try {
|
try {
|
||||||
r->leftTrack->Get(
|
r->leftTrack->GetFloats(
|
||||||
(samplePtr)(r->leftBuffer.get()), floatSample, r->offset, blockSize);
|
(r->leftBuffer.get()), r->offset, blockSize);
|
||||||
r->rightTrack->Get(
|
r->rightTrack->GetFloats(
|
||||||
(samplePtr)(r->rightBuffer.get()), floatSample, r->offset, blockSize);
|
(r->rightBuffer.get()), r->offset, blockSize);
|
||||||
}
|
}
|
||||||
catch ( ... ) {
|
catch ( ... ) {
|
||||||
// Save the exception object for re-throw when out of the library
|
// Save the exception object for re-throw when out of the library
|
||||||
|
@ -96,7 +96,7 @@ bool EffectSimpleMono::ProcessOne(WaveTrack * track,
|
|||||||
limitSampleBufferSize( track->GetBestBlockSize(s), end - s );
|
limitSampleBufferSize( track->GetBestBlockSize(s), end - s );
|
||||||
|
|
||||||
//Get the samples from the track and put them in the buffer
|
//Get the samples from the track and put them in the buffer
|
||||||
track->Get((samplePtr) buffer.get(), floatSample, s, block);
|
track->GetFloats(buffer.get(), s, block);
|
||||||
|
|
||||||
//Process the buffer. If it fails, clean up and exit.
|
//Process the buffer. If it fails, clean up and exit.
|
||||||
if (!ProcessSimpleMono(buffer.get(), block))
|
if (!ProcessSimpleMono(buffer.get(), block))
|
||||||
|
@ -217,7 +217,7 @@ bool EffectSoundTouch::ProcessOne(WaveTrack *track,
|
|||||||
limitSampleBufferSize( track->GetBestBlockSize(s), end - s ));
|
limitSampleBufferSize( track->GetBestBlockSize(s), end - s ));
|
||||||
|
|
||||||
//Get the samples from the track and put them in the buffer
|
//Get the samples from the track and put them in the buffer
|
||||||
track->Get((samplePtr)buffer.get(), floatSample, s, block);
|
track->GetFloats(buffer.get(), s, block);
|
||||||
|
|
||||||
//Add samples to SoundTouch
|
//Add samples to SoundTouch
|
||||||
mSoundTouch->putSamples(buffer.get(), block);
|
mSoundTouch->putSamples(buffer.get(), block);
|
||||||
@ -298,8 +298,8 @@ bool EffectSoundTouch::ProcessStereo(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Get the samples from the tracks and put them in the buffers.
|
// Get the samples from the tracks and put them in the buffers.
|
||||||
leftTrack->Get((samplePtr)(leftBuffer.get()), floatSample, sourceSampleCount, blockSize);
|
leftTrack->GetFloats((leftBuffer.get()), sourceSampleCount, blockSize);
|
||||||
rightTrack->Get((samplePtr)(rightBuffer.get()), floatSample, sourceSampleCount, blockSize);
|
rightTrack->GetFloats((rightBuffer.get()), sourceSampleCount, blockSize);
|
||||||
|
|
||||||
// Interleave into soundTouchBuffer.
|
// Interleave into soundTouchBuffer.
|
||||||
for (decltype(blockSize) index = 0; index < blockSize; index++) {
|
for (decltype(blockSize) index = 0; index < blockSize; index++) {
|
||||||
|
@ -568,8 +568,8 @@ bool EffectTruncSilence::DoRemoval
|
|||||||
auto t1 = wt->TimeToLongSamples(cutStart) - blendFrames / 2;
|
auto t1 = wt->TimeToLongSamples(cutStart) - blendFrames / 2;
|
||||||
auto t2 = wt->TimeToLongSamples(cutEnd) - blendFrames / 2;
|
auto t2 = wt->TimeToLongSamples(cutEnd) - blendFrames / 2;
|
||||||
|
|
||||||
wt->Get((samplePtr)buf1.get(), floatSample, t1, blendFrames);
|
wt->GetFloats(buf1.get(), t1, blendFrames);
|
||||||
wt->Get((samplePtr)buf2.get(), floatSample, t2, blendFrames);
|
wt->GetFloats(buf2.get(), t2, blendFrames);
|
||||||
|
|
||||||
for (decltype(blendFrames) i = 0; i < blendFrames; ++i)
|
for (decltype(blendFrames) i = 0; i < blendFrames; ++i)
|
||||||
{
|
{
|
||||||
@ -689,7 +689,7 @@ bool EffectTruncSilence::Analyze(RegionList& silenceList,
|
|||||||
auto count = limitSampleBufferSize( blockLen, end - *index );
|
auto count = limitSampleBufferSize( blockLen, end - *index );
|
||||||
|
|
||||||
// Fill buffer
|
// Fill buffer
|
||||||
wt->Get((samplePtr)(buffer.get()), floatSample, *index, count);
|
wt->GetFloats((buffer.get()), *index, count);
|
||||||
|
|
||||||
// Look for silenceList in current block
|
// Look for silenceList in current block
|
||||||
for (decltype(count) i = 0; i < count; ++i) {
|
for (decltype(count) i = 0; i < count; ++i) {
|
||||||
|
@ -130,7 +130,7 @@ bool EffectTwoPassSimpleMono::ProcessOne(WaveTrack * track, WaveTrack * outTrack
|
|||||||
std::min( maxblock, track->GetBestBlockSize(start) ), end - start );
|
std::min( maxblock, track->GetBestBlockSize(start) ), end - start );
|
||||||
|
|
||||||
//Get the samples from the track and put them in the buffer
|
//Get the samples from the track and put them in the buffer
|
||||||
track->Get((samplePtr) buffer1.get(), floatSample, start, samples1);
|
track->GetFloats(buffer1.get(), start, samples1);
|
||||||
|
|
||||||
// Process the first buffer with a NULL previous buffer
|
// Process the first buffer with a NULL previous buffer
|
||||||
if (mPass == 0)
|
if (mPass == 0)
|
||||||
@ -152,7 +152,7 @@ bool EffectTwoPassSimpleMono::ProcessOne(WaveTrack * track, WaveTrack * outTrack
|
|||||||
);
|
);
|
||||||
|
|
||||||
//Get the samples from the track and put them in the buffer
|
//Get the samples from the track and put them in the buffer
|
||||||
track->Get((samplePtr)buffer2.get(), floatSample, s, samples2);
|
track->GetFloats(buffer2.get(), s, samples2);
|
||||||
|
|
||||||
//Process the buffer. If it fails, clean up and exit.
|
//Process the buffer. If it fails, clean up and exit.
|
||||||
if (mPass == 0)
|
if (mPass == 0)
|
||||||
|
@ -29,6 +29,7 @@ effects from this one class.
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
|
||||||
@ -1390,12 +1391,12 @@ bool NyquistEffect::ProcessOne()
|
|||||||
|
|
||||||
// Put the fetch buffers in a clean initial state
|
// Put the fetch buffers in a clean initial state
|
||||||
for (size_t i = 0; i < mCurNumChannels; i++)
|
for (size_t i = 0; i < mCurNumChannels; i++)
|
||||||
mCurBuffer[i].Free();
|
mCurBuffer[i].reset();
|
||||||
|
|
||||||
// Guarantee release of memory when done
|
// Guarantee release of memory when done
|
||||||
auto cleanup = finally( [&] {
|
auto cleanup = finally( [&] {
|
||||||
for (size_t i = 0; i < mCurNumChannels; i++)
|
for (size_t i = 0; i < mCurNumChannels; i++)
|
||||||
mCurBuffer[i].Free();
|
mCurBuffer[i].reset();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// Evaluate the expression, which may invoke the get callback, but often does
|
// Evaluate the expression, which may invoke the get callback, but often does
|
||||||
@ -1563,7 +1564,7 @@ bool NyquistEffect::ProcessOne()
|
|||||||
|
|
||||||
// Clean the initial buffer states again for the get callbacks
|
// Clean the initial buffer states again for the get callbacks
|
||||||
// -- is this really needed?
|
// -- is this really needed?
|
||||||
mCurBuffer[i].Free();
|
mCurBuffer[i].reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now fully evaluate the sound
|
// Now fully evaluate the sound
|
||||||
@ -2426,15 +2427,15 @@ int NyquistEffect::StaticGetCallback(float *buffer, int channel,
|
|||||||
int NyquistEffect::GetCallback(float *buffer, int ch,
|
int NyquistEffect::GetCallback(float *buffer, int ch,
|
||||||
int64_t start, int64_t len, int64_t WXUNUSED(totlen))
|
int64_t start, int64_t len, int64_t WXUNUSED(totlen))
|
||||||
{
|
{
|
||||||
if (mCurBuffer[ch].ptr()) {
|
if (mCurBuffer[ch]) {
|
||||||
if ((mCurStart[ch] + start) < mCurBufferStart[ch] ||
|
if ((mCurStart[ch] + start) < mCurBufferStart[ch] ||
|
||||||
(mCurStart[ch] + start)+len >
|
(mCurStart[ch] + start)+len >
|
||||||
mCurBufferStart[ch]+mCurBufferLen[ch]) {
|
mCurBufferStart[ch]+mCurBufferLen[ch]) {
|
||||||
mCurBuffer[ch].Free();
|
mCurBuffer[ch].reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mCurBuffer[ch].ptr()) {
|
if (!mCurBuffer[ch]) {
|
||||||
mCurBufferStart[ch] = (mCurStart[ch] + start);
|
mCurBufferStart[ch] = (mCurStart[ch] + start);
|
||||||
mCurBufferLen[ch] = mCurTrack[ch]->GetBestBlockSize(mCurBufferStart[ch]);
|
mCurBufferLen[ch] = mCurTrack[ch]->GetBestBlockSize(mCurBufferStart[ch]);
|
||||||
|
|
||||||
@ -2446,10 +2447,11 @@ int NyquistEffect::GetCallback(float *buffer, int ch,
|
|||||||
limitSampleBufferSize( mCurBufferLen[ch],
|
limitSampleBufferSize( mCurBufferLen[ch],
|
||||||
mCurStart[ch] + mCurLen - mCurBufferStart[ch] );
|
mCurStart[ch] + mCurLen - mCurBufferStart[ch] );
|
||||||
|
|
||||||
mCurBuffer[ch].Allocate(mCurBufferLen[ch], floatSample);
|
// C++20
|
||||||
|
// mCurBuffer[ch] = std::make_unique_for_overwrite(mCurBufferLen[ch]);
|
||||||
|
mCurBuffer[ch] = Buffer{ safenew float[ mCurBufferLen[ch] ] };
|
||||||
try {
|
try {
|
||||||
mCurTrack[ch]->Get(
|
mCurTrack[ch]->GetFloats( mCurBuffer[ch].get(),
|
||||||
mCurBuffer[ch].ptr(), floatSample,
|
|
||||||
mCurBufferStart[ch], mCurBufferLen[ch]);
|
mCurBufferStart[ch], mCurBufferLen[ch]);
|
||||||
}
|
}
|
||||||
catch ( ... ) {
|
catch ( ... ) {
|
||||||
@ -2462,9 +2464,8 @@ int NyquistEffect::GetCallback(float *buffer, int ch,
|
|||||||
// We have guaranteed above that this is nonnegative and bounded by
|
// We have guaranteed above that this is nonnegative and bounded by
|
||||||
// mCurBufferLen[ch]:
|
// mCurBufferLen[ch]:
|
||||||
auto offset = ( mCurStart[ch] + start - mCurBufferStart[ch] ).as_size_t();
|
auto offset = ( mCurStart[ch] + start - mCurBufferStart[ch] ).as_size_t();
|
||||||
CopySamples(mCurBuffer[ch].ptr() + offset*SAMPLE_SIZE(floatSample), floatSample,
|
const void *src = &mCurBuffer[ch][offset];
|
||||||
(samplePtr)buffer, floatSample,
|
std::memcpy(buffer, src, len * sizeof(float));
|
||||||
len);
|
|
||||||
|
|
||||||
if (ch == 0) {
|
if (ch == 0) {
|
||||||
double progress = mScale *
|
double progress = mScale *
|
||||||
|
@ -267,7 +267,8 @@ private:
|
|||||||
double mProgressTot;
|
double mProgressTot;
|
||||||
double mScale;
|
double mScale;
|
||||||
|
|
||||||
SampleBuffer mCurBuffer[2];
|
using Buffer = std::unique_ptr<float[]>;
|
||||||
|
Buffer mCurBuffer[2];
|
||||||
sampleCount mCurBufferStart[2];
|
sampleCount mCurBufferStart[2];
|
||||||
size_t mCurBufferLen[2];
|
size_t mCurBufferLen[2];
|
||||||
|
|
||||||
|
@ -453,12 +453,12 @@ bool VampEffect::Process()
|
|||||||
|
|
||||||
if (left)
|
if (left)
|
||||||
{
|
{
|
||||||
left->Get((samplePtr)data[0].get(), floatSample, pos, request);
|
left->GetFloats(data[0].get(), pos, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (right)
|
if (right)
|
||||||
{
|
{
|
||||||
right->Get((samplePtr)data[1].get(), floatSample, pos, request);
|
right->GetFloats(data[1].get(), pos, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request < block)
|
if (request < block)
|
||||||
|
@ -643,12 +643,13 @@ ProgressResult ExportPCM::Export(AudacityProject *project,
|
|||||||
CopySamples(
|
CopySamples(
|
||||||
mixed + (c * SAMPLE_SIZE(format)), format,
|
mixed + (c * SAMPLE_SIZE(format)), format,
|
||||||
dither.data() + (c * SAMPLE_SIZE(int24Sample)), int24Sample,
|
dither.data() + (c * SAMPLE_SIZE(int24Sample)), int24Sample,
|
||||||
numSamples, true, info.channels, info.channels
|
numSamples, gHighQualityDither, info.channels, info.channels
|
||||||
);
|
);
|
||||||
CopySamplesNoDither(
|
// Copy back without dither
|
||||||
|
CopySamples(
|
||||||
dither.data() + (c * SAMPLE_SIZE(int24Sample)), int24Sample,
|
dither.data() + (c * SAMPLE_SIZE(int24Sample)), int24Sample,
|
||||||
mixed + (c * SAMPLE_SIZE(format)), format,
|
mixed + (c * SAMPLE_SIZE(format)), format,
|
||||||
numSamples, info.channels, info.channels);
|
numSamples, DitherType::none, info.channels, info.channels);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,6 +221,10 @@ private:
|
|||||||
AUPImportPlugin::AUPImportPlugin()
|
AUPImportPlugin::AUPImportPlugin()
|
||||||
: ImportPlugin(FileExtensions(exts.begin(), exts.end()))
|
: ImportPlugin(FileExtensions(exts.begin(), exts.end()))
|
||||||
{
|
{
|
||||||
|
static_assert(
|
||||||
|
sizeof(long long) >= sizeof(uint64_t) &&
|
||||||
|
sizeof(long) >= sizeof(uint32_t),
|
||||||
|
"Assumptions about sizes in XMLValueChecker calls are invalid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
AUPImportPlugin::~AUPImportPlugin()
|
AUPImportPlugin::~AUPImportPlugin()
|
||||||
@ -643,8 +647,6 @@ bool AUPImportFileHandle::HandleProject(XMLTagHandler *&handler)
|
|||||||
{
|
{
|
||||||
const wxChar *attr = *mAttrs++;
|
const wxChar *attr = *mAttrs++;
|
||||||
const wxChar *value = *mAttrs++;
|
const wxChar *value = *mAttrs++;
|
||||||
long lValue;
|
|
||||||
long long llValue;
|
|
||||||
double dValue;
|
double dValue;
|
||||||
|
|
||||||
if (!value)
|
if (!value)
|
||||||
@ -664,6 +666,7 @@ bool AUPImportFileHandle::HandleProject(XMLTagHandler *&handler)
|
|||||||
// ViewInfo
|
// ViewInfo
|
||||||
if (!wxStrcmp(attr, wxT("vpos")))
|
if (!wxStrcmp(attr, wxT("vpos")))
|
||||||
{
|
{
|
||||||
|
long lValue;
|
||||||
if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&lValue) || (lValue < 0))
|
if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&lValue) || (lValue < 0))
|
||||||
{
|
{
|
||||||
return SetError(XO("Invalid project 'vpos' attribute."));
|
return SetError(XO("Invalid project 'vpos' attribute."));
|
||||||
@ -1115,14 +1118,13 @@ bool AUPImportFileHandle::HandleSequence(XMLTagHandler *&handler)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
long long nValue = 0;
|
|
||||||
|
|
||||||
const wxString strValue = value; // promote string, we need this for all
|
const wxString strValue = value; // promote string, we need this for all
|
||||||
|
|
||||||
if (!wxStrcmp(attr, wxT("maxsamples")))
|
if (!wxStrcmp(attr, wxT("maxsamples")))
|
||||||
{
|
{
|
||||||
// This attribute is a sample count, so can be 64bit
|
// This attribute is a sample count, so can be 64bit
|
||||||
if (!XMLValueChecker::IsGoodInt64(strValue) || !strValue.ToLongLong(&nValue) || (nValue < 0))
|
long long llvalue;
|
||||||
|
if (!XMLValueChecker::IsGoodInt64(strValue) || !strValue.ToLongLong(&llvalue) || (llvalue < 0))
|
||||||
{
|
{
|
||||||
return SetError(XO("Invalid sequence 'maxsamples' attribute."));
|
return SetError(XO("Invalid sequence 'maxsamples' attribute."));
|
||||||
}
|
}
|
||||||
@ -1130,7 +1132,7 @@ bool AUPImportFileHandle::HandleSequence(XMLTagHandler *&handler)
|
|||||||
// Dominic, 12/10/2006:
|
// Dominic, 12/10/2006:
|
||||||
// Let's check that maxsamples is >= 1024 and <= 64 * 1024 * 1024
|
// Let's check that maxsamples is >= 1024 and <= 64 * 1024 * 1024
|
||||||
// - that's a pretty wide range of reasonable values.
|
// - that's a pretty wide range of reasonable values.
|
||||||
if ((nValue < 1024) || (nValue > 64 * 1024 * 1024))
|
if ((llvalue < 1024) || (llvalue > 64 * 1024 * 1024))
|
||||||
{
|
{
|
||||||
return SetError(XO("Invalid sequence 'maxsamples' attribute."));
|
return SetError(XO("Invalid sequence 'maxsamples' attribute."));
|
||||||
}
|
}
|
||||||
@ -1150,7 +1152,8 @@ bool AUPImportFileHandle::HandleSequence(XMLTagHandler *&handler)
|
|||||||
else if (!wxStrcmp(attr, wxT("numsamples")))
|
else if (!wxStrcmp(attr, wxT("numsamples")))
|
||||||
{
|
{
|
||||||
// This attribute is a sample count, so can be 64bit
|
// This attribute is a sample count, so can be 64bit
|
||||||
if (!XMLValueChecker::IsGoodInt64(strValue) || !strValue.ToLongLong(&nValue) || (nValue < 0))
|
long long llvalue;
|
||||||
|
if (!XMLValueChecker::IsGoodInt64(strValue) || !strValue.ToLongLong(&llvalue) || (llvalue < 0))
|
||||||
{
|
{
|
||||||
return SetError(XO("Invalid sequence 'numsamples' attribute."));
|
return SetError(XO("Invalid sequence 'numsamples' attribute."));
|
||||||
}
|
}
|
||||||
@ -1169,8 +1172,6 @@ bool AUPImportFileHandle::HandleWaveBlock(XMLTagHandler *&handler)
|
|||||||
const wxChar *attr = *mAttrs++;
|
const wxChar *attr = *mAttrs++;
|
||||||
const wxChar *value = *mAttrs++;
|
const wxChar *value = *mAttrs++;
|
||||||
|
|
||||||
long long nValue = 0;
|
|
||||||
|
|
||||||
if (!value)
|
if (!value)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
@ -1181,7 +1182,8 @@ bool AUPImportFileHandle::HandleWaveBlock(XMLTagHandler *&handler)
|
|||||||
if (!wxStrcmp(attr, wxT("start")))
|
if (!wxStrcmp(attr, wxT("start")))
|
||||||
{
|
{
|
||||||
// making sure that values > 2^31 are OK because long clips will need them.
|
// making sure that values > 2^31 are OK because long clips will need them.
|
||||||
if (!XMLValueChecker::IsGoodInt64(strValue) || !strValue.ToLongLong(&nValue) || (nValue < 0))
|
long long llvalue;
|
||||||
|
if (!XMLValueChecker::IsGoodInt64(strValue) || !strValue.ToLongLong(&llvalue) || (llvalue < 0))
|
||||||
{
|
{
|
||||||
return SetError(XO("Unable to parse the waveblock 'start' attribute"));
|
return SetError(XO("Unable to parse the waveblock 'start' attribute"));
|
||||||
}
|
}
|
||||||
@ -1196,13 +1198,12 @@ bool AUPImportFileHandle::HandleWaveBlock(XMLTagHandler *&handler)
|
|||||||
bool AUPImportFileHandle::HandleSimpleBlockFile(XMLTagHandler *&handler)
|
bool AUPImportFileHandle::HandleSimpleBlockFile(XMLTagHandler *&handler)
|
||||||
{
|
{
|
||||||
FilePath filename;
|
FilePath filename;
|
||||||
sampleCount len = 0;
|
size_t len = 0;
|
||||||
|
|
||||||
while (*mAttrs)
|
while (*mAttrs)
|
||||||
{
|
{
|
||||||
const wxChar *attr = *mAttrs++;
|
const wxChar *attr = *mAttrs++;
|
||||||
const wxChar *value = *mAttrs++;
|
const wxChar *value = *mAttrs++;
|
||||||
long long nValue;
|
|
||||||
|
|
||||||
if (!value)
|
if (!value)
|
||||||
{
|
{
|
||||||
@ -1229,12 +1230,13 @@ bool AUPImportFileHandle::HandleSimpleBlockFile(XMLTagHandler *&handler)
|
|||||||
}
|
}
|
||||||
else if (!wxStrcmp(attr, wxT("len")))
|
else if (!wxStrcmp(attr, wxT("len")))
|
||||||
{
|
{
|
||||||
if (!XMLValueChecker::IsGoodInt64(strValue) || !strValue.ToLongLong(&nValue) || (nValue <= 0))
|
long lValue;
|
||||||
|
if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&lValue) || (lValue <= 0))
|
||||||
{
|
{
|
||||||
return SetError(XO("Missing or invalid simpleblockfile 'len' attribute."));
|
return SetError(XO("Missing or invalid simpleblockfile 'len' attribute."));
|
||||||
}
|
}
|
||||||
|
|
||||||
len = nValue;
|
len = lValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1248,13 +1250,12 @@ bool AUPImportFileHandle::HandleSimpleBlockFile(XMLTagHandler *&handler)
|
|||||||
bool AUPImportFileHandle::HandleSilentBlockFile(XMLTagHandler *&handler)
|
bool AUPImportFileHandle::HandleSilentBlockFile(XMLTagHandler *&handler)
|
||||||
{
|
{
|
||||||
FilePath filename;
|
FilePath filename;
|
||||||
sampleCount len = 0;
|
size_t len = 0;
|
||||||
|
|
||||||
while (*mAttrs)
|
while (*mAttrs)
|
||||||
{
|
{
|
||||||
const wxChar *attr = *mAttrs++;
|
const wxChar *attr = *mAttrs++;
|
||||||
const wxChar *value = *mAttrs++;
|
const wxChar *value = *mAttrs++;
|
||||||
long long nValue;
|
|
||||||
|
|
||||||
if (!value)
|
if (!value)
|
||||||
{
|
{
|
||||||
@ -1265,12 +1266,13 @@ bool AUPImportFileHandle::HandleSilentBlockFile(XMLTagHandler *&handler)
|
|||||||
|
|
||||||
if (!wxStrcmp(attr, wxT("len")))
|
if (!wxStrcmp(attr, wxT("len")))
|
||||||
{
|
{
|
||||||
if (!XMLValueChecker::IsGoodInt64(value) || !strValue.ToLongLong(&nValue) || !(nValue > 0))
|
long lValue;
|
||||||
|
if (!XMLValueChecker::IsGoodInt(value) || !strValue.ToLong(&lValue) || !(lValue > 0))
|
||||||
{
|
{
|
||||||
return SetError(XO("Missing or invalid silentblockfile 'len' attribute."));
|
return SetError(XO("Missing or invalid silentblockfile 'len' attribute."));
|
||||||
}
|
}
|
||||||
|
|
||||||
len = nValue;
|
len = lValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1286,7 +1288,7 @@ bool AUPImportFileHandle::HandlePCMAliasBlockFile(XMLTagHandler *&handler)
|
|||||||
wxString summaryFilename;
|
wxString summaryFilename;
|
||||||
wxFileName filename;
|
wxFileName filename;
|
||||||
sampleCount start = 0;
|
sampleCount start = 0;
|
||||||
sampleCount len = 0;
|
size_t len = 0;
|
||||||
int channel = 0;
|
int channel = 0;
|
||||||
wxString name;
|
wxString name;
|
||||||
|
|
||||||
@ -1294,7 +1296,6 @@ bool AUPImportFileHandle::HandlePCMAliasBlockFile(XMLTagHandler *&handler)
|
|||||||
{
|
{
|
||||||
const wxChar *attr = *mAttrs++;
|
const wxChar *attr = *mAttrs++;
|
||||||
const wxChar *value = *mAttrs++;
|
const wxChar *value = *mAttrs++;
|
||||||
long long nValue;
|
|
||||||
|
|
||||||
if (!value)
|
if (!value)
|
||||||
{
|
{
|
||||||
@ -1328,31 +1329,33 @@ bool AUPImportFileHandle::HandlePCMAliasBlockFile(XMLTagHandler *&handler)
|
|||||||
}
|
}
|
||||||
else if (!wxStricmp(attr, wxT("aliasstart")))
|
else if (!wxStricmp(attr, wxT("aliasstart")))
|
||||||
{
|
{
|
||||||
if (!XMLValueChecker::IsGoodInt64(strValue) || !strValue.ToLongLong(&nValue) || (nValue < 0))
|
long long llValue;
|
||||||
|
if (!XMLValueChecker::IsGoodInt64(strValue) || !strValue.ToLongLong(&llValue) || (llValue < 0))
|
||||||
{
|
{
|
||||||
return SetError(XO("Missing or invalid pcmaliasblockfile 'aliasstart' attribute."));
|
return SetError(XO("Missing or invalid pcmaliasblockfile 'aliasstart' attribute."));
|
||||||
}
|
}
|
||||||
|
|
||||||
start = nValue;
|
start = llValue;
|
||||||
}
|
}
|
||||||
else if (!wxStricmp(attr, wxT("aliaslen")))
|
else if (!wxStricmp(attr, wxT("aliaslen")))
|
||||||
{
|
{
|
||||||
if (!XMLValueChecker::IsGoodInt64(strValue) || !strValue.ToLongLong(&nValue) || (nValue <= 0))
|
long lValue;
|
||||||
|
if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&lValue) || (lValue <= 0))
|
||||||
{
|
{
|
||||||
return SetError(XO("Missing or invalid pcmaliasblockfile 'aliaslen' attribute."));
|
return SetError(XO("Missing or invalid pcmaliasblockfile 'aliaslen' attribute."));
|
||||||
}
|
}
|
||||||
|
|
||||||
len = nValue;
|
len = lValue;
|
||||||
}
|
}
|
||||||
else if (!wxStricmp(attr, wxT("aliaschannel")))
|
else if (!wxStricmp(attr, wxT("aliaschannel")))
|
||||||
{
|
{
|
||||||
long nValue;
|
long lValue;
|
||||||
if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&nValue) || (nValue < 0))
|
if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&lValue) || (lValue < 0))
|
||||||
{
|
{
|
||||||
return SetError(XO("Missing or invalid pcmaliasblockfile 'aliaslen' attribute."));
|
return SetError(XO("Missing or invalid pcmaliasblockfile 'aliaslen' attribute."));
|
||||||
}
|
}
|
||||||
|
|
||||||
channel = nValue;
|
channel = lValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1512,6 +1515,12 @@ bool AUPImportFileHandle::AddSamples(const FilePath &blockFilename,
|
|||||||
|
|
||||||
auto cleanup = finally([&]
|
auto cleanup = finally([&]
|
||||||
{
|
{
|
||||||
|
// Do this before any throwing might happen
|
||||||
|
if (sf)
|
||||||
|
{
|
||||||
|
SFCall<int>(sf_close, sf);
|
||||||
|
}
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
SetWarning(XO("Error while processing %s\n\nInserting silence.").Format(audioFilename));
|
SetWarning(XO("Error while processing %s\n\nInserting silence.").Format(audioFilename));
|
||||||
@ -1522,11 +1531,6 @@ bool AUPImportFileHandle::AddSamples(const FilePath &blockFilename,
|
|||||||
// If this does throw, let that propagate, don't guard the call
|
// If this does throw, let that propagate, don't guard the call
|
||||||
AddSilence(len);
|
AddSilence(len);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sf)
|
|
||||||
{
|
|
||||||
SFCall<int>(sf_close, sf);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!f.Open(audioFilename))
|
if (!f.Open(audioFilename))
|
||||||
@ -1569,6 +1573,8 @@ bool AUPImportFileHandle::AddSamples(const FilePath &blockFilename,
|
|||||||
|
|
||||||
size_t framesRead = 0;
|
size_t framesRead = 0;
|
||||||
|
|
||||||
|
// These cases preserve the logic formerly in BlockFile.cpp,
|
||||||
|
// which was deleted at commit 98d1468.
|
||||||
if (channels == 1 && format == int16Sample && sf_subtype_is_integer(info.format))
|
if (channels == 1 && format == int16Sample && sf_subtype_is_integer(info.format))
|
||||||
{
|
{
|
||||||
// If both the src and dest formats are integer formats,
|
// If both the src and dest formats are integer formats,
|
||||||
@ -1620,6 +1626,18 @@ bool AUPImportFileHandle::AddSamples(const FilePath &blockFilename,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
Therefore none of the three cases above:
|
||||||
|
!(channels == 1 && format == int16Sample && sf_subtype_is_integer(info.format))
|
||||||
|
&&
|
||||||
|
!(channels == 1 && format == int24Sample && sf_subtype_is_integer(info.format))
|
||||||
|
&&
|
||||||
|
!(format == int16Sample && !sf_subtype_more_than_16_bits(info.format))
|
||||||
|
|
||||||
|
So format is not 16 bits with wider file format (third conjunct),
|
||||||
|
but still maybe it is 24 bits with float file format (second conjunct).
|
||||||
|
*/
|
||||||
|
|
||||||
// Otherwise, let libsndfile handle the conversion and
|
// Otherwise, let libsndfile handle the conversion and
|
||||||
// scaling, and pass us normalized data as floats. We can
|
// scaling, and pass us normalized data as floats. We can
|
||||||
// then convert to whatever format we want.
|
// then convert to whatever format we want.
|
||||||
@ -1635,12 +1653,25 @@ bool AUPImportFileHandle::AddSamples(const FilePath &blockFilename,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Dithering will happen in CopySamples if format is 24 bits.
|
||||||
|
Should that be done?
|
||||||
|
|
||||||
|
Either the file is an ordinary simple block file -- and presumably the
|
||||||
|
track was saved specifying a matching format, so format is float and
|
||||||
|
there is no dithering.
|
||||||
|
|
||||||
|
Or else this is the very unusual case of an .auf file, importing PCM data
|
||||||
|
on demand. The destination format is narrower, requiring dither, only
|
||||||
|
if the user also specified a narrow format for the track. In such a
|
||||||
|
case, dithering is right.
|
||||||
|
*/
|
||||||
CopySamples((samplePtr)(tmpptr + channel),
|
CopySamples((samplePtr)(tmpptr + channel),
|
||||||
floatSample,
|
floatSample,
|
||||||
bufptr,
|
bufptr,
|
||||||
format,
|
format,
|
||||||
framesRead,
|
framesRead,
|
||||||
true /* high quality by default */,
|
gHighQualityDither /* high quality by default */,
|
||||||
channels /* source stride */);
|
channels /* source stride */);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ double NearestZeroCrossing
|
|||||||
auto s = one->TimeToLongSamples(t0);
|
auto s = one->TimeToLongSamples(t0);
|
||||||
// fillTwo to ensure that missing values are treated as 2, and hence do
|
// fillTwo to ensure that missing values are treated as 2, and hence do
|
||||||
// not get used as zero crossings.
|
// not get used as zero crossings.
|
||||||
one->Get((samplePtr)oneDist.get(), floatSample,
|
one->GetFloats(oneDist.get(),
|
||||||
s - (int)oneWindowSize/2, oneWindowSize, fillTwo);
|
s - (int)oneWindowSize/2, oneWindowSize, fillTwo);
|
||||||
|
|
||||||
|
|
||||||
|
@ -593,7 +593,7 @@ void OnPunchAndRoll(const CommandContext &context)
|
|||||||
if (getLen > 0) {
|
if (getLen > 0) {
|
||||||
float *const samples = data.data();
|
float *const samples = data.data();
|
||||||
const sampleCount pos = wt->TimeToLongSamples(t1);
|
const sampleCount pos = wt->TimeToLongSamples(t1);
|
||||||
wt->Get((samplePtr)samples, floatSample, pos, getLen);
|
wt->GetFloats(samples, pos, getLen);
|
||||||
}
|
}
|
||||||
crossfadeData.push_back(std::move(data));
|
crossfadeData.push_back(std::move(data));
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ UIHandlePtr SampleHandle::HitTest
|
|||||||
float oneSample;
|
float oneSample;
|
||||||
const double rate = wavetrack->GetRate();
|
const double rate = wavetrack->GetRate();
|
||||||
const auto s0 = (sampleCount)(tt * rate + 0.5);
|
const auto s0 = (sampleCount)(tt * rate + 0.5);
|
||||||
if (! wavetrack->Get((samplePtr)&oneSample, floatSample, s0, 1, fillZero,
|
if (! wavetrack->GetFloats(&oneSample, s0, 1, fillZero,
|
||||||
// Do not propagate exception but return a failure value
|
// Do not propagate exception but return a failure value
|
||||||
false) )
|
false) )
|
||||||
return {};
|
return {};
|
||||||
@ -238,7 +238,7 @@ UIHandle::Result SampleHandle::Click
|
|||||||
Floats newSampleRegion{ 1 + 2 * (size_t)SMOOTHING_BRUSH_RADIUS };
|
Floats newSampleRegion{ 1 + 2 * (size_t)SMOOTHING_BRUSH_RADIUS };
|
||||||
|
|
||||||
//Get a sample from the track to do some tricks on.
|
//Get a sample from the track to do some tricks on.
|
||||||
mClickedTrack->Get((samplePtr)sampleRegion.get(), floatSample,
|
mClickedTrack->GetFloats(sampleRegion.get(),
|
||||||
mClickedStartSample - SMOOTHING_KERNEL_RADIUS - SMOOTHING_BRUSH_RADIUS,
|
mClickedStartSample - SMOOTHING_KERNEL_RADIUS - SMOOTHING_BRUSH_RADIUS,
|
||||||
sampleRegionSize);
|
sampleRegionSize);
|
||||||
|
|
||||||
|
@ -1364,9 +1364,9 @@ void SelectHandle::StartSnappingFreqSelection
|
|||||||
end - start));
|
end - start));
|
||||||
const auto effectiveLength = std::max(minLength, length);
|
const auto effectiveLength = std::max(minLength, length);
|
||||||
frequencySnappingData.resize(effectiveLength, 0.0f);
|
frequencySnappingData.resize(effectiveLength, 0.0f);
|
||||||
pTrack->Get(
|
pTrack->GetFloats(
|
||||||
reinterpret_cast<samplePtr>(&frequencySnappingData[0]),
|
&frequencySnappingData[0],
|
||||||
floatSample, start, length, fillZero,
|
start, length, fillZero,
|
||||||
// Don't try to cope with exceptions, just read zeroes instead.
|
// Don't try to cope with exceptions, just read zeroes instead.
|
||||||
false);
|
false);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user