1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-14 15:20:29 +02:00

Merge pull request #923 from Paul-Licameli/Review-of-dithering

Review of dithering
This commit is contained in:
Paul Licameli 2021-05-27 11:40:28 -04:00 committed by GitHub
commit 428506ea2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 305 additions and 192 deletions

View File

@ -3622,11 +3622,9 @@ static void DoSoftwarePlaythrough(const void *inputBuffer,
{
for (unsigned int i=0; i < inputChannels; i++) {
samplePtr inputPtr = ((samplePtr)inputBuffer) + (i * SAMPLE_SIZE(inputFormat));
samplePtr outputPtr = ((samplePtr)outputBuffer) + (i * SAMPLE_SIZE(floatSample));
CopySamples(inputPtr, inputFormat,
(samplePtr)outputPtr, floatSample,
len, true, inputChannels, 2);
SamplesToFloats(inputPtr, inputFormat,
outputBuffer + i, len, inputChannels, 2);
}
// One mono input channel goes to both output channels...
@ -4411,9 +4409,8 @@ int AudioIoCallback::AudioCallback(const void *inputBuffer, void *outputBuffer,
inputSamples = (float *) inputBuffer;
}
else {
CopySamples((samplePtr)inputBuffer, mCaptureFormat,
(samplePtr)tempFloats, floatSample,
framesPerBuffer * numCaptureChannels);
SamplesToFloats(reinterpret_cast<constSamplePtr>(inputBuffer),
mCaptureFormat, tempFloats, framesPerBuffer * numCaptureChannels);
inputSamples = tempFloats;
}

View File

@ -602,7 +602,7 @@ void FrequencyPlotDialog::GetAudio()
mDataLen = dataLen.as_size_t();
mData = Floats{ mDataLen };
// Don't allow throw for bad reads
track->Get((samplePtr)mData.get(), floatSample, start, mDataLen,
track->GetFloats(mData.get(), start, mDataLen,
fillZero, false);
}
else {
@ -617,7 +617,7 @@ void FrequencyPlotDialog::GetAudio()
auto start = track->TimeToLongSamples(selectedRegion.t0());
Floats buffer2{ mDataLen };
// Again, stop exceptions
track->Get((samplePtr)buffer2.get(), floatSample, start, mDataLen,
track->GetFloats(buffer2.get(), start, mDataLen,
fillZero, false);
for (size_t i = 0; i < mDataLen; i++)
mData[i] += buffer2[i];

View File

@ -460,7 +460,8 @@ size_t Mixer::MixVariableRates(int *channelFlags, WaveTrackCache &cache,
// Nothing to do if past end of play interval
if (getLen > 0) {
if (backwards) {
auto results = cache.Get(floatSample, *pos - (getLen - 1), getLen, mMayThrow);
auto results =
cache.GetFloats(*pos - (getLen - 1), getLen, mMayThrow);
if (results)
memcpy(&queue[*queueLen], results, sizeof(float) * getLen);
else
@ -472,7 +473,7 @@ size_t Mixer::MixVariableRates(int *channelFlags, WaveTrackCache &cache,
*pos -= getLen;
}
else {
auto results = cache.Get(floatSample, *pos, getLen, mMayThrow);
auto results = cache.GetFloats(*pos, getLen, mMayThrow);
if (results)
memcpy(&queue[*queueLen], results, sizeof(float) * getLen);
else
@ -589,7 +590,7 @@ size_t Mixer::MixSameRate(int *channelFlags, WaveTrackCache &cache,
);
if (backwards) {
auto results = cache.Get(floatSample, *pos - (slen - 1), slen, mMayThrow);
auto results = cache.GetFloats(*pos - (slen - 1), slen, mMayThrow);
if (results)
memcpy(mFloatBuffer.get(), results, sizeof(float) * slen);
else
@ -602,7 +603,7 @@ size_t Mixer::MixSameRate(int *channelFlags, WaveTrackCache &cache,
*pos -= slen;
}
else {
auto results = cache.Get(floatSample, *pos, slen, mMayThrow);
auto results = cache.GetFloats(*pos, slen, mMayThrow);
if (results)
memcpy(mFloatBuffer.get(), results, sizeof(float) * slen);
else
@ -691,7 +692,7 @@ size_t Mixer::Process(size_t maxToProcess)
mBuffer[0].ptr() + (c * SAMPLE_SIZE(mFormat)),
mFormat,
maxOut,
mHighQuality,
mHighQuality ? gHighQualityDither : gLowQualityDither,
mNumChannels,
mNumChannels);
}
@ -703,7 +704,7 @@ size_t Mixer::Process(size_t maxToProcess)
mBuffer[c].ptr(),
mFormat,
maxOut,
mHighQuality);
mHighQuality ? gHighQualityDither : gLowQualityDither);
}
}
// MB: this doesn't take warping into account, replaced with code based on mSamplePos

View File

@ -610,8 +610,8 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
Floats tempFloatsArray{ nFrames };
decltype(tempFloatsArray) meterFloatsArray;
// Don't throw on read error in this drawing update routine
bool bSuccess = pTrack->Get((samplePtr)tempFloatsArray.get(),
floatSample, startSample, nFrames, fillZero, false);
bool bSuccess = pTrack->GetFloats(tempFloatsArray.get(),
startSample, nFrames, fillZero, false);
if (bSuccess)
{
// 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())
// Again, don't throw
bSuccess = GetRight()->Get((samplePtr)tempFloatsArray.get(),
floatSample, startSample, nFrames, fillZero, false);
bSuccess = GetRight()->GetFloats(tempFloatsArray.get(),
startSample, nFrames, fillZero, false);
if (bSuccess)
// Interleave right channel, or duplicate same signal for "right" channel in mono case.

View File

@ -85,7 +85,7 @@ size_t RingBuffer::Put(samplePtr buffer, sampleFormat format,
CopySamples(src, format,
mBuffer.ptr() + pos * SAMPLE_SIZE(mFormat), mFormat,
block);
block, DitherType::none);
src += block * SAMPLE_SIZE(format);
pos = (pos + block) % mBufferSize;
@ -167,7 +167,7 @@ size_t RingBuffer::Get(samplePtr buffer, sampleFormat format,
CopySamples(mBuffer.ptr() + start * SAMPLE_SIZE(mFormat), mFormat,
dest, format,
block);
block, DitherType::none);
dest += block * SAMPLE_SIZE(format);
start = (start + block) % mBufferSize;

View File

@ -24,6 +24,7 @@ class RingBuffer {
//
size_t AvailForPut();
//! Does not apply dithering
size_t Put(samplePtr buffer, sampleFormat format, size_t samples,
// optional number of trailing zeroes
size_t padding = 0);
@ -34,6 +35,7 @@ class RingBuffer {
//
size_t AvailForGet();
//! Does not apply dithering
size_t Get(samplePtr buffer, sampleFormat format, size_t samples);
size_t Discard(size_t samples);

View File

@ -43,11 +43,10 @@
#include <string.h>
#include "Prefs.h"
#include "Dither.h"
#include "Internat.h"
static DitherType gLowQualityDither = DitherType::none;
static DitherType gHighQualityDither = DitherType::none;
DitherType gLowQualityDither = DitherType::none;
DitherType gHighQualityDither = DitherType::shaped;
static Dither gDitherAlgorithm;
void InitDitherers()
@ -99,25 +98,22 @@ void ReverseSamples(samplePtr dst, sampleFormat format,
}
}
void CopySamples(constSamplePtr src, sampleFormat srcFormat,
samplePtr dst, sampleFormat dstFormat,
unsigned int len,
bool highQuality, /* = true */
unsigned int srcStride /* = 1 */,
unsigned int dstStride /* = 1 */)
void SamplesToFloats(constSamplePtr src, sampleFormat srcFormat,
float *dst, size_t len, size_t srcStride, size_t dstStride)
{
gDitherAlgorithm.Apply(
highQuality ? gHighQualityDither : gLowQualityDither,
src, srcFormat, dst, dstFormat, len, srcStride, dstStride);
CopySamples( src, srcFormat,
reinterpret_cast<samplePtr>(dst), floatSample, len,
DitherType::none,
srcStride, dstStride);
}
void CopySamplesNoDither(samplePtr src, sampleFormat srcFormat,
samplePtr dst, sampleFormat dstFormat,
unsigned int len,
unsigned int srcStride /* = 1 */,
unsigned int dstStride /* = 1 */)
void CopySamples(constSamplePtr src, sampleFormat srcFormat,
samplePtr dst, sampleFormat dstFormat, size_t len,
DitherType ditherType, /* = gHighQualityDither */
unsigned int srcStride /* = 1 */,
unsigned int dstStride /* = 1 */)
{
gDitherAlgorithm.Apply(
DitherType::none,
ditherType,
src, srcFormat, dst, dstFormat, len, srcStride, dstStride);
}

View File

@ -2,7 +2,7 @@
Audacity: A Digital Audio Editor
SampleFormat.h
@file SampleFormat.h
Dominic Mazzoni
@ -17,11 +17,15 @@
#include <wx/defs.h>
#include "audacity/Types.h"
#include "Dither.h"
//
// 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
// Moved to audacity/types.h
typedef enum {
@ -125,18 +129,29 @@ private:
//
AUDACITY_DLL_API
void CopySamples(constSamplePtr src, sampleFormat srcFormat,
samplePtr dst, sampleFormat dstFormat,
unsigned int len, bool highQuality=true,
unsigned int srcStride=1,
unsigned int dstStride=1);
//! Copy samples from any format into the widest format, which is 32 bit float, with no dithering
/*!
@param src address of source samples
@param srcFormat format of source samples, determines sizeof each one
@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
void CopySamplesNoDither(samplePtr src, sampleFormat srcFormat,
samplePtr dst, sampleFormat dstFormat,
unsigned int len,
unsigned int srcStride=1,
unsigned int dstStride=1);
//! Copy samples from any format to any other format; apply dithering only if narrowing the format
/*!
@copydetails SamplesToFloats()
@param dstFormat format of destination samples, determines sizeof each one
@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
void ClearSamples(samplePtr buffer, sampleFormat format,

View File

@ -593,6 +593,42 @@ size_t SqliteSampleBlock::GetBlob(void *dest,
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,
srcformat,
(samplePtr) dest,
@ -806,11 +842,8 @@ void SqliteSampleBlock::CalcSummary(Sizes sizes)
else
{
samplebuffer.reinit((unsigned) mSampleCount);
CopySamples(mSamples.get(),
mSampleFormat,
(samplePtr) samplebuffer.get(),
floatSample,
mSampleCount);
SamplesToFloats(mSamples.get(), mSampleFormat,
samplebuffer.get(), mSampleCount);
samples = samplebuffer.get();
}

View File

@ -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();
//Only go through the first SignalWindowSizeInt samples, and choose the first that trips the key.
Floats buffer{ remaining };
t.Get((samplePtr)buffer.get(), floatSample,
t.GetFloats(buffer.get(),
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();
//Only go through the first mSilentWindowSizeInt samples, and choose the first that trips the key.
Floats buffer{ remaining };
t.Get((samplePtr)buffer.get(), floatSample,
t.GetFloats(buffer.get(),
lastsubthresholdsample - remaining, remaining);
//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();
//Only go through the first SilentWindowSizeInt samples, and choose the first that trips the key.
Floats buffer{ remaining };
t.Get((samplePtr)buffer.get(), floatSample,
t.GetFloats(buffer.get(),
lastsubthresholdsample, remaining);
//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();
//Only go through the first SilentWindowSizeInt samples, and choose the first that trips the key.
Floats buffer{ remaining };
t.Get((samplePtr)buffer.get(), floatSample,
t.GetFloats(buffer.get(),
lastsubthresholdsample - remaining, remaining);
//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
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
for(decltype(block) i = 0; i< block; i++)
@ -913,7 +913,7 @@ double VoiceKey::TestSignChanges(
//Figure out how much to grab
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)
{
@ -970,7 +970,7 @@ double VoiceKey::TestDirectionChanges(
//Figure out how much to grab
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) {
//The first time through, set stuff up special.

View File

@ -525,9 +525,9 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0,
else {
b.reinit(len);
pb = b.get();
CopySamples(mAppendBuffer.ptr() + sLeft * SAMPLE_SIZE(seqFormat),
seqFormat,
(samplePtr)pb, floatSample, len);
SamplesToFloats(
mAppendBuffer.ptr() + sLeft * SAMPLE_SIZE(seqFormat),
seqFormat, pb, len);
}
float theMax, theMin, sumsq;
@ -707,8 +707,8 @@ bool SpecCache::CalculateOneSpectrum
}
if (myLen > 0) {
useBuffer = (float*)(waveTrackCache.Get(
floatSample, sampleCount(
useBuffer = (float*)(waveTrackCache.GetFloats(
sampleCount(
floor(0.5 + from.as_double() + offset * rate)
),
myLen,
@ -1248,7 +1248,7 @@ bool WaveClip::Append(constSamplePtr buffer, sampleFormat format,
mAppendBuffer.ptr() + mAppendBufferLen * SAMPLE_SIZE(seqFormat),
seqFormat,
toCopy,
true, // high quality
gHighQualityDither,
stride);
mAppendBufferLen += toCopy;

View File

@ -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)
{
constexpr auto format = floatSample;
if (format == floatSample && len > 0) {
const auto end = start + len;
@ -2593,10 +2594,10 @@ constSamplePtr WaveTrackCache::Get(sampleFormat format,
if (start0 >= 0) {
const auto len0 = mPTrack->GetBestBlockSize(start0);
wxASSERT(len0 <= mBufferSize);
if (!mPTrack->Get(
samplePtr(mBuffers[0].data.get()), floatSample, start0, len0,
if (!mPTrack->GetFloats(
mBuffers[0].data.get(), start0, len0,
fillZero, mayThrow))
return 0;
return nullptr;
mBuffers[0].start = start0;
mBuffers[0].len = len0;
if (!fillSecond &&
@ -2621,8 +2622,8 @@ constSamplePtr WaveTrackCache::Get(sampleFormat format,
if (start1 == end0) {
const auto len1 = mPTrack->GetBestBlockSize(start1);
wxASSERT(len1 <= mBufferSize);
if (!mPTrack->Get(samplePtr(mBuffers[1].data.get()), floatSample, start1, len1, fillZero, mayThrow))
return 0;
if (!mPTrack->GetFloats(mBuffers[1].data.get(), start1, len1, fillZero, mayThrow))
return nullptr;
mBuffers[1].start = start1;
mBuffers[1].len = len1;
mNValidBuffers = 2;
@ -2631,7 +2632,7 @@ constSamplePtr WaveTrackCache::Get(sampleFormat format,
}
wxASSERT(mNValidBuffers < 2 || mBuffers[0].end() == mBuffers[1].start);
samplePtr buffer = 0;
samplePtr buffer = nullptr; // will point into mOverlapBuffer
auto remaining = len;
// Possibly get an initial portion that is uncached
@ -2646,9 +2647,11 @@ constSamplePtr WaveTrackCache::Get(sampleFormat format,
mOverlapBuffer.Resize(len, format);
// initLen is not more than len:
auto sinitLen = initLen.as_size_t();
if (!mPTrack->Get(mOverlapBuffer.ptr(), format, start, sinitLen,
fillZero, mayThrow))
return 0;
if (!mPTrack->GetFloats(
// See comment below about casting
reinterpret_cast<float *>(mOverlapBuffer.ptr()),
start, sinitLen, fillZero, mayThrow))
return nullptr;
wxASSERT( sinitLen <= remaining );
remaining -= sinitLen;
start += initLen;
@ -2669,12 +2672,12 @@ constSamplePtr WaveTrackCache::Get(sampleFormat format,
// All is contiguous already. We can completely avoid copying
// leni is nonnegative, therefore start falls within mBuffers[ii],
// 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) {
// leni is nonnegative, therefore start falls within mBuffers[ii]
// But we can't satisfy all from one buffer, so copy
if (buffer == 0) {
if (!buffer) {
mOverlapBuffer.Resize(len, format);
buffer = mOverlapBuffer.ptr();
}
@ -2692,23 +2695,31 @@ constSamplePtr WaveTrackCache::Get(sampleFormat format,
if (remaining > 0) {
// Very big request!
// Fall back to direct fetch
if (buffer == 0) {
if (!buffer) {
mOverlapBuffer.Resize(len, format);
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 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.
mOverlapBuffer.Resize(len, format);
if (mPTrack->Get(mOverlapBuffer.ptr(), format, start, len, fillZero, mayThrow))
return mOverlapBuffer.ptr();
#else
// No longer handling other than float format. Therefore len is 0.
#endif
return nullptr;
}
// Cache works only for float format.
mOverlapBuffer.Resize(len, format);
if (mPTrack->Get(mOverlapBuffer.ptr(), format, start, len, fillZero, mayThrow))
return mOverlapBuffer.ptr();
else
return 0;
}
void WaveTrackCache::Free()

View File

@ -246,6 +246,31 @@ private:
/// same value for "start" in both calls to "Set" and "Get" it is
/// 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,
sampleCount start, size_t len,
fillFormat fill = fillZero,
@ -254,6 +279,7 @@ private:
// filled according to fillFormat; but these were not necessarily one
// contiguous range.
sampleCount * pNumWithinClips = nullptr) const;
void Set(constSamplePtr buffer, sampleFormat format,
sampleCount start, size_t len);
@ -592,10 +618,9 @@ private:
std::unique_ptr<WaveformSettings> mpWaveformSettings;
};
// This is meant to be a short-lived object, during whose lifetime,
// the contents of the WaveTrack are known not to change. It can replace
// repeated calls to WaveTrack::Get() (each of which opens and closes at least
// one block file).
//! A short-lived object, during whose lifetime, the contents of the WaveTrack are assumed not to change.
/*! It can replace repeated calls to WaveTrack::Get() (each of which opens and closes at least one block).
*/
class AUDACITY_DLL_API WaveTrackCache {
public:
WaveTrackCache()
@ -617,12 +642,11 @@ public:
const std::shared_ptr<const WaveTrack>& GetTrack() const { return mPTrack; }
void SetTrack(const std::shared_ptr<const WaveTrack> &pTrack);
// Uses fillZero always
// Returns null on failure
// Returned pointer may be invalidated if Get is called again
// Do not DELETE[] the pointer
constSamplePtr Get(
sampleFormat format, sampleCount start, size_t len, bool mayThrow);
//! Retrieve samples as floats from the track or from the memory cache
/*! Uses fillZero always
@return null on failure; this object owns the memory; may be invalidated if GetFloats() is called again
*/
const float *GetFloats(sampleCount start, size_t len, bool mayThrow);
private:
void Free();

View File

@ -138,8 +138,8 @@ bool CompareAudioCommand::Apply(const CommandContext & context)
auto block = limitSampleBufferSize(
mTrack0->GetBestBlockSize(position), s1 - position
);
mTrack0->Get((samplePtr)buff0.get(), floatSample, position, block);
mTrack1->Get((samplePtr)buff1.get(), floatSample, position, block);
mTrack0->GetFloats(buff0.get(), position, block);
mTrack1->GetFloats(buff1.get(), position, block);
for (decltype(block) buffPos = 0; buffPos < block; ++buffPos)
{

View File

@ -321,7 +321,7 @@ bool EffectAutoDuck::Process()
{
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++)
{
@ -559,7 +559,7 @@ bool EffectAutoDuck::ApplyDuckFade(int trackNum, WaveTrack* t,
{
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++)
{

View File

@ -477,7 +477,7 @@ void EffectChangePitch::DeduceFrequencies()
Floats freq{ windowSize / 2 };
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++) {
ComputeSpectrum(buffer.get() + i * windowSize, windowSize,
windowSize, rate, freq.get(), true);

View File

@ -520,7 +520,7 @@ bool EffectChangeSpeed::ProcessOne(WaveTrack * track,
);
//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,
inBuffer.get(),

View File

@ -233,7 +233,7 @@ bool EffectClickRemoval::ProcessOne(int count, WaveTrack * track, sampleCount st
{
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)
{

View File

@ -1637,10 +1637,10 @@ bool Effect::ProcessTrack(int count,
limitSampleBufferSize( mBufferSize, inputRemaining );
// Fill the input buffers
left->Get((samplePtr) inBuffer[0].get(), floatSample, inPos, inputBufferCnt);
left->GetFloats(inBuffer[0].get(), inPos, inputBufferCnt);
if (right)
{
right->Get((samplePtr) inBuffer[1].get(), floatSample, inPos, inputBufferCnt);
right->GetFloats(inBuffer[1].get(), inPos, inputBufferCnt);
}
// Reset the input buffer positions

View File

@ -1330,7 +1330,7 @@ bool EffectEqualization::ProcessOne(int count, WaveTrack * t,
{
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
{

View File

@ -198,7 +198,7 @@ bool EffectFindClipping::ProcessOne(LabelTrack * lt,
block = limitSampleBufferSize( blockSize, len - s );
wt->Get((samplePtr)buffer.get(), floatSample, start + s, block);
wt->GetFloats(buffer.get(), start + s, block);
ptr = buffer.get();
}

View File

@ -515,7 +515,7 @@ void EffectLoudness::LoadBufferBlock(TrackIterRange<WaveTrack> range,
int idx = 0;
for(auto channel : range)
{
channel->Get((samplePtr) mTrackBuffer[idx].get(), floatSample, pos, len );
channel->GetFloats(mTrackBuffer[idx].get(), pos, len );
++idx;
}
mTrackBufferLen = len;

View File

@ -1330,7 +1330,7 @@ bool EffectNoiseReduction::Worker::ProcessOne
);
//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;
mInSampleCount += blockSize;

View File

@ -435,7 +435,7 @@ bool EffectNormalize::AnalyseTrackData(const WaveTrack * track, const Translatab
);
//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;
//Process the buffer.
@ -495,7 +495,7 @@ bool EffectNormalize::ProcessOne(
);
//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.
ProcessData(buffer.get(), block, offset);

View File

@ -359,7 +359,7 @@ bool EffectPaulstretch::ProcessOne(WaveTrack *track,double t0,double t1,int coun
decltype(len) s=0;
while (s < len) {
track->Get((samplePtr)bufferptr0, floatSample, start + s, nget);
track->GetFloats(bufferptr0, start + s, nget);
stretch.process(buffer0.get(), nget);
if (first_time) {
@ -369,7 +369,7 @@ bool EffectPaulstretch::ProcessOne(WaveTrack *track,double t0,double t1,int coun
s += nget;
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;
for (size_t i = 0; i < fade_len; i++){
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
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++){
float fi = (float)i / (float)fade_len;
auto i2 = bufsize / 2 - 1 - i;

View File

@ -146,7 +146,7 @@ bool EffectRepair::ProcessOne(int count, WaveTrack * track,
size_t repairStart, size_t repairLen)
{
Floats buffer{ len };
track->Get((samplePtr) buffer.get(), floatSample, start, len);
track->GetFloats(buffer.get(), start, len);
InterpolateAudio(buffer.get(), len, repairStart, repairLen);
track->Set((samplePtr)&buffer[repairStart], floatSample,
start + repairStart, repairLen);

View File

@ -232,8 +232,8 @@ bool EffectReverse::ProcessOneClip(int count, WaveTrack *track,
limitSampleBufferSize( track->GetBestBlockSize(first), len / 2 );
auto second = first + (len - block);
track->Get((samplePtr)buffer1.get(), floatSample, first, block);
track->Get((samplePtr)buffer2.get(), floatSample, second, block);
track->GetFloats(buffer1.get(), first, block);
track->GetFloats(buffer2.get(), second, block);
for (decltype(block) i = 0; i < block; i++) {
tmp = buffer1[i];
buffer1[i] = buffer2[block-i-1];

View File

@ -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
// stop the effect early.
try {
r->leftTrack->Get(
(samplePtr)(r->leftBuffer.get()), floatSample, r->offset, blockSize);
r->rightTrack->Get(
(samplePtr)(r->rightBuffer.get()), floatSample, r->offset, blockSize);
r->leftTrack->GetFloats(
(r->leftBuffer.get()), r->offset, blockSize);
r->rightTrack->GetFloats(
(r->rightBuffer.get()), r->offset, blockSize);
}
catch ( ... ) {
// Save the exception object for re-throw when out of the library

View File

@ -96,7 +96,7 @@ bool EffectSimpleMono::ProcessOne(WaveTrack * track,
limitSampleBufferSize( track->GetBestBlockSize(s), end - s );
//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.
if (!ProcessSimpleMono(buffer.get(), block))

View File

@ -217,7 +217,7 @@ bool EffectSoundTouch::ProcessOne(WaveTrack *track,
limitSampleBufferSize( track->GetBestBlockSize(s), end - s ));
//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
mSoundTouch->putSamples(buffer.get(), block);
@ -298,8 +298,8 @@ bool EffectSoundTouch::ProcessStereo(
);
// Get the samples from the tracks and put them in the buffers.
leftTrack->Get((samplePtr)(leftBuffer.get()), floatSample, sourceSampleCount, blockSize);
rightTrack->Get((samplePtr)(rightBuffer.get()), floatSample, sourceSampleCount, blockSize);
leftTrack->GetFloats((leftBuffer.get()), sourceSampleCount, blockSize);
rightTrack->GetFloats((rightBuffer.get()), sourceSampleCount, blockSize);
// Interleave into soundTouchBuffer.
for (decltype(blockSize) index = 0; index < blockSize; index++) {

View File

@ -568,8 +568,8 @@ bool EffectTruncSilence::DoRemoval
auto t1 = wt->TimeToLongSamples(cutStart) - blendFrames / 2;
auto t2 = wt->TimeToLongSamples(cutEnd) - blendFrames / 2;
wt->Get((samplePtr)buf1.get(), floatSample, t1, blendFrames);
wt->Get((samplePtr)buf2.get(), floatSample, t2, blendFrames);
wt->GetFloats(buf1.get(), t1, blendFrames);
wt->GetFloats(buf2.get(), t2, blendFrames);
for (decltype(blendFrames) i = 0; i < blendFrames; ++i)
{
@ -689,7 +689,7 @@ bool EffectTruncSilence::Analyze(RegionList& silenceList,
auto count = limitSampleBufferSize( blockLen, end - *index );
// Fill buffer
wt->Get((samplePtr)(buffer.get()), floatSample, *index, count);
wt->GetFloats((buffer.get()), *index, count);
// Look for silenceList in current block
for (decltype(count) i = 0; i < count; ++i) {

View File

@ -130,7 +130,7 @@ bool EffectTwoPassSimpleMono::ProcessOne(WaveTrack * track, WaveTrack * outTrack
std::min( maxblock, track->GetBestBlockSize(start) ), end - start );
//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
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
track->Get((samplePtr)buffer2.get(), floatSample, s, samples2);
track->GetFloats(buffer2.get(), s, samples2);
//Process the buffer. If it fails, clean up and exit.
if (mPass == 0)

View File

@ -29,6 +29,7 @@ effects from this one class.
#include <algorithm>
#include <cmath>
#include <cstring>
#include <locale.h>
@ -1390,12 +1391,12 @@ bool NyquistEffect::ProcessOne()
// Put the fetch buffers in a clean initial state
for (size_t i = 0; i < mCurNumChannels; i++)
mCurBuffer[i].Free();
mCurBuffer[i].reset();
// Guarantee release of memory when done
auto cleanup = finally( [&] {
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
@ -1563,7 +1564,7 @@ bool NyquistEffect::ProcessOne()
// Clean the initial buffer states again for the get callbacks
// -- is this really needed?
mCurBuffer[i].Free();
mCurBuffer[i].reset();
}
// Now fully evaluate the sound
@ -2426,15 +2427,15 @@ int NyquistEffect::StaticGetCallback(float *buffer, int channel,
int NyquistEffect::GetCallback(float *buffer, int ch,
int64_t start, int64_t len, int64_t WXUNUSED(totlen))
{
if (mCurBuffer[ch].ptr()) {
if (mCurBuffer[ch]) {
if ((mCurStart[ch] + start) < mCurBufferStart[ch] ||
(mCurStart[ch] + start)+len >
mCurBufferStart[ch]+mCurBufferLen[ch]) {
mCurBuffer[ch].Free();
mCurBuffer[ch].reset();
}
}
if (!mCurBuffer[ch].ptr()) {
if (!mCurBuffer[ch]) {
mCurBufferStart[ch] = (mCurStart[ch] + start);
mCurBufferLen[ch] = mCurTrack[ch]->GetBestBlockSize(mCurBufferStart[ch]);
@ -2446,10 +2447,11 @@ int NyquistEffect::GetCallback(float *buffer, int ch,
limitSampleBufferSize( mCurBufferLen[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 {
mCurTrack[ch]->Get(
mCurBuffer[ch].ptr(), floatSample,
mCurTrack[ch]->GetFloats( mCurBuffer[ch].get(),
mCurBufferStart[ch], mCurBufferLen[ch]);
}
catch ( ... ) {
@ -2462,9 +2464,8 @@ int NyquistEffect::GetCallback(float *buffer, int ch,
// We have guaranteed above that this is nonnegative and bounded by
// mCurBufferLen[ch]:
auto offset = ( mCurStart[ch] + start - mCurBufferStart[ch] ).as_size_t();
CopySamples(mCurBuffer[ch].ptr() + offset*SAMPLE_SIZE(floatSample), floatSample,
(samplePtr)buffer, floatSample,
len);
const void *src = &mCurBuffer[ch][offset];
std::memcpy(buffer, src, len * sizeof(float));
if (ch == 0) {
double progress = mScale *

View File

@ -267,7 +267,8 @@ private:
double mProgressTot;
double mScale;
SampleBuffer mCurBuffer[2];
using Buffer = std::unique_ptr<float[]>;
Buffer mCurBuffer[2];
sampleCount mCurBufferStart[2];
size_t mCurBufferLen[2];

View File

@ -453,12 +453,12 @@ bool VampEffect::Process()
if (left)
{
left->Get((samplePtr)data[0].get(), floatSample, pos, request);
left->GetFloats(data[0].get(), pos, request);
}
if (right)
{
right->Get((samplePtr)data[1].get(), floatSample, pos, request);
right->GetFloats(data[1].get(), pos, request);
}
if (request < block)

View File

@ -643,12 +643,13 @@ ProgressResult ExportPCM::Export(AudacityProject *project,
CopySamples(
mixed + (c * SAMPLE_SIZE(format)), format,
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,
mixed + (c * SAMPLE_SIZE(format)), format,
numSamples, info.channels, info.channels);
numSamples, DitherType::none, info.channels, info.channels);
}
}

View File

@ -221,6 +221,10 @@ private:
AUPImportPlugin::AUPImportPlugin()
: 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()
@ -643,8 +647,6 @@ bool AUPImportFileHandle::HandleProject(XMLTagHandler *&handler)
{
const wxChar *attr = *mAttrs++;
const wxChar *value = *mAttrs++;
long lValue;
long long llValue;
double dValue;
if (!value)
@ -664,6 +666,7 @@ bool AUPImportFileHandle::HandleProject(XMLTagHandler *&handler)
// ViewInfo
if (!wxStrcmp(attr, wxT("vpos")))
{
long lValue;
if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&lValue) || (lValue < 0))
{
return SetError(XO("Invalid project 'vpos' attribute."));
@ -1115,14 +1118,13 @@ bool AUPImportFileHandle::HandleSequence(XMLTagHandler *&handler)
break;
}
long long nValue = 0;
const wxString strValue = value; // promote string, we need this for all
if (!wxStrcmp(attr, wxT("maxsamples")))
{
// 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."));
}
@ -1130,7 +1132,7 @@ bool AUPImportFileHandle::HandleSequence(XMLTagHandler *&handler)
// Dominic, 12/10/2006:
// Let's check that maxsamples is >= 1024 and <= 64 * 1024 * 1024
// - 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."));
}
@ -1150,7 +1152,8 @@ bool AUPImportFileHandle::HandleSequence(XMLTagHandler *&handler)
else if (!wxStrcmp(attr, wxT("numsamples")))
{
// 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."));
}
@ -1169,8 +1172,6 @@ bool AUPImportFileHandle::HandleWaveBlock(XMLTagHandler *&handler)
const wxChar *attr = *mAttrs++;
const wxChar *value = *mAttrs++;
long long nValue = 0;
if (!value)
{
break;
@ -1181,7 +1182,8 @@ bool AUPImportFileHandle::HandleWaveBlock(XMLTagHandler *&handler)
if (!wxStrcmp(attr, wxT("start")))
{
// 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"));
}
@ -1196,13 +1198,12 @@ bool AUPImportFileHandle::HandleWaveBlock(XMLTagHandler *&handler)
bool AUPImportFileHandle::HandleSimpleBlockFile(XMLTagHandler *&handler)
{
FilePath filename;
sampleCount len = 0;
size_t len = 0;
while (*mAttrs)
{
const wxChar *attr = *mAttrs++;
const wxChar *value = *mAttrs++;
long long nValue;
if (!value)
{
@ -1229,12 +1230,13 @@ bool AUPImportFileHandle::HandleSimpleBlockFile(XMLTagHandler *&handler)
}
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."));
}
len = nValue;
len = lValue;
}
}
@ -1248,13 +1250,12 @@ bool AUPImportFileHandle::HandleSimpleBlockFile(XMLTagHandler *&handler)
bool AUPImportFileHandle::HandleSilentBlockFile(XMLTagHandler *&handler)
{
FilePath filename;
sampleCount len = 0;
size_t len = 0;
while (*mAttrs)
{
const wxChar *attr = *mAttrs++;
const wxChar *value = *mAttrs++;
long long nValue;
if (!value)
{
@ -1265,12 +1266,13 @@ bool AUPImportFileHandle::HandleSilentBlockFile(XMLTagHandler *&handler)
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."));
}
len = nValue;
len = lValue;
}
}
@ -1286,7 +1288,7 @@ bool AUPImportFileHandle::HandlePCMAliasBlockFile(XMLTagHandler *&handler)
wxString summaryFilename;
wxFileName filename;
sampleCount start = 0;
sampleCount len = 0;
size_t len = 0;
int channel = 0;
wxString name;
@ -1294,7 +1296,6 @@ bool AUPImportFileHandle::HandlePCMAliasBlockFile(XMLTagHandler *&handler)
{
const wxChar *attr = *mAttrs++;
const wxChar *value = *mAttrs++;
long long nValue;
if (!value)
{
@ -1328,31 +1329,33 @@ bool AUPImportFileHandle::HandlePCMAliasBlockFile(XMLTagHandler *&handler)
}
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."));
}
start = nValue;
start = llValue;
}
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."));
}
len = nValue;
len = lValue;
}
else if (!wxStricmp(attr, wxT("aliaschannel")))
{
long nValue;
if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&nValue) || (nValue < 0))
long lValue;
if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&lValue) || (lValue < 0))
{
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([&]
{
// Do this before any throwing might happen
if (sf)
{
SFCall<int>(sf_close, sf);
}
if (!success)
{
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
AddSilence(len);
}
if (sf)
{
SFCall<int>(sf_close, sf);
}
});
if (!f.Open(audioFilename))
@ -1569,6 +1573,8 @@ bool AUPImportFileHandle::AddSamples(const FilePath &blockFilename,
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 both the src and dest formats are integer formats,
@ -1620,6 +1626,18 @@ bool AUPImportFileHandle::AddSamples(const FilePath &blockFilename,
}
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
// scaling, and pass us normalized data as floats. We can
// then convert to whatever format we want.
@ -1635,12 +1653,25 @@ bool AUPImportFileHandle::AddSamples(const FilePath &blockFilename,
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),
floatSample,
bufptr,
format,
framesRead,
true /* high quality by default */,
gHighQualityDither /* high quality by default */,
channels /* source stride */);
}

View File

@ -70,7 +70,7 @@ double NearestZeroCrossing
auto s = one->TimeToLongSamples(t0);
// fillTwo to ensure that missing values are treated as 2, and hence do
// not get used as zero crossings.
one->Get((samplePtr)oneDist.get(), floatSample,
one->GetFloats(oneDist.get(),
s - (int)oneWindowSize/2, oneWindowSize, fillTwo);

View File

@ -593,7 +593,7 @@ void OnPunchAndRoll(const CommandContext &context)
if (getLen > 0) {
float *const samples = data.data();
const sampleCount pos = wt->TimeToLongSamples(t1);
wt->Get((samplePtr)samples, floatSample, pos, getLen);
wt->GetFloats(samples, pos, getLen);
}
crossfadeData.push_back(std::move(data));
}

View File

@ -127,7 +127,7 @@ UIHandlePtr SampleHandle::HitTest
float oneSample;
const double rate = wavetrack->GetRate();
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
false) )
return {};
@ -238,7 +238,7 @@ UIHandle::Result SampleHandle::Click
Floats newSampleRegion{ 1 + 2 * (size_t)SMOOTHING_BRUSH_RADIUS };
//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,
sampleRegionSize);

View File

@ -1364,9 +1364,9 @@ void SelectHandle::StartSnappingFreqSelection
end - start));
const auto effectiveLength = std::max(minLength, length);
frequencySnappingData.resize(effectiveLength, 0.0f);
pTrack->Get(
reinterpret_cast<samplePtr>(&frequencySnappingData[0]),
floatSample, start, length, fillZero,
pTrack->GetFloats(
&frequencySnappingData[0],
start, length, fillZero,
// Don't try to cope with exceptions, just read zeroes instead.
false);