Audacity  2.2.2
Public Types | Public Member Functions | Private Member Functions | Private Attributes | Static Private Attributes | List of all members
Dither Class Reference

This class implements various functions for dithering and is derived from the dither code in the Ardour project, written by Steve Harris. More...

#include <Dither.h>

Public Types

enum  DitherType { none = 0, rectangle = 1, triangle = 2, shaped = 3 }
 These ditherers are currently available: More...
 

Public Member Functions

 Dither ()
 Default constructor. More...
 
void Reset ()
 Reset state of the dither. More...
 
void Apply (DitherType ditherType, const samplePtr source, sampleFormat sourceFormat, samplePtr dest, sampleFormat destFormat, unsigned int len, unsigned int sourceStride=1, unsigned int destStride=1)
 

Private Member Functions

float NoDither (float sample)
 
float RectangleDither (float sample)
 
float TriangleDither (float sample)
 
float ShapedDither (float sample)
 

Private Attributes

int mPhase
 
float mTriangleState
 
float mBuffer [8]
 

Static Private Attributes

static const int BUF_SIZE = 8
 
static const int BUF_MASK = 7
 
static const float SHAPED_BS [] = { 2.033f, -2.165f, 1.959f, -1.590f, 0.6149f }
 

Detailed Description

This class implements various functions for dithering and is derived from the dither code in the Ardour project, written by Steve Harris.

Dithering is only done if it really is necessary. Otherwise (e.g. when the source and destination format of the samples is the same), the samples are only copied or converted. However, copied samples are always checked for out-of-bounds values and possibly clipped accordingly.

These dither algorithms are currently implemented:

Dither class. You must construct an instance because it keeps state. Call Dither::Apply() to apply the dither. You can call Reset() between subsequent dithers to reset the dither state and get deterministic behaviour.

Definition at line 16 of file Dither.h.

Member Enumeration Documentation

These ditherers are currently available:

Enumerator
none 
rectangle 
triangle 
shaped 

Definition at line 23 of file Dither.h.

Constructor & Destructor Documentation

Dither::Dither ( )

Default constructor.

Definition at line 207 of file Dither.cpp.

References Reset().

208 {
209  // On startup, initialize dither by resetting values
210  Reset();
211 }
void Reset()
Reset state of the dither.
Definition: Dither.cpp:213

Member Function Documentation

void Dither::Apply ( DitherType  ditherType,
const samplePtr  source,
sampleFormat  sourceFormat,
samplePtr  dest,
sampleFormat  destFormat,
unsigned int  len,
unsigned int  sourceStride = 1,
unsigned int  destStride = 1 
)

Apply the actual dithering. Expects the source sample in the 'source' variable, the destination sample in the 'dest' variable, and hints to the formats of the samples. Even if the sample formats are the same, samples are clipped, if necessary.

Definition at line 236 of file Dither.cpp.

References DITHER, FROM_INT16, FROM_INT24, NoDither(), none, rectangle, RectangleDither(), Reset(), shaped, ShapedDither(), triangle, and TriangleDither().

Referenced by CopySamples(), and CopySamplesNoDither().

242 {
243  unsigned int i;
244 
245  // This code is not designed for 16-bit or 64-bit machine
246  wxASSERT(sizeof(int) == 4);
247  wxASSERT(sizeof(short) == 2);
248 
249  // Check parameters
250  wxASSERT(source);
251  wxASSERT(dest);
252  wxASSERT(len >= 0);
253  wxASSERT(sourceStride > 0);
254  wxASSERT(destStride > 0);
255 
256  if (len == 0)
257  return; // nothing to do
258 
259  if (destFormat == sourceFormat)
260  {
261  // No need to dither, because source and destination
262  // format are the same. Just copy samples.
263  if (destStride == 1 && sourceStride == 1)
264  memcpy(dest, source, len * SAMPLE_SIZE(destFormat));
265  else
266  {
267  if (sourceFormat == floatSample)
268  {
269  float* d = (float*)dest;
270  float* s = (float*)source;
271 
272  for (i = 0; i < len; i++, d += destStride, s += sourceStride)
273  *d = *s;
274  } else
275  if (sourceFormat == int24Sample)
276  {
277  int* d = (int*)dest;
278  int* s = (int*)source;
279 
280  for (i = 0; i < len; i++, d += destStride, s += sourceStride)
281  *d = *s;
282  } else
283  if (sourceFormat == int16Sample)
284  {
285  short* d = (short*)dest;
286  short* s = (short*)source;
287 
288  for (i = 0; i < len; i++, d += destStride, s += sourceStride)
289  *d = *s;
290  } else {
291  wxASSERT(false); // source format unknown
292  }
293  }
294  } else
295  if (destFormat == floatSample)
296  {
297  // No need to dither, just convert samples to float.
298  // No clipping should be necessary.
299  float* d = (float*)dest;
300 
301  if (sourceFormat == int16Sample)
302  {
303  short* s = (short*)source;
304  for (i = 0; i < len; i++, d += destStride, s += sourceStride)
305  *d = FROM_INT16(s);
306  } else
307  if (sourceFormat == int24Sample)
308  {
309  int* s = (int*)source;
310  for (i = 0; i < len; i++, d += destStride, s += sourceStride)
311  *d = FROM_INT24(s);
312  } else {
313  wxASSERT(false); // source format unknown
314  }
315  } else
316  if (destFormat == int24Sample && sourceFormat == int16Sample)
317  {
318  // Special case when promoting 16 bit to 24 bit
319  int* d = (int*)dest;
320  short* s = (short*)source;
321  for (i = 0; i < len; i++, d += destStride, s += sourceStride)
322  *d = ((int)*s) << 8;
323  } else
324  {
325  // We must do dithering
326  switch (ditherType)
327  {
328  case none:
329  DITHER(NoDither, dest, destFormat, destStride, source, sourceFormat, sourceStride, len);
330  break;
331  case rectangle:
332  DITHER(RectangleDither, dest, destFormat, destStride, source, sourceFormat, sourceStride, len);
333  break;
334  case triangle:
335  Reset(); // reset dither filter for this NEW conversion
336  DITHER(TriangleDither, dest, destFormat, destStride, source, sourceFormat, sourceStride, len);
337  break;
338  case shaped:
339  Reset(); // reset dither filter for this NEW conversion
340  DITHER(ShapedDither, dest, destFormat, destStride, source, sourceFormat, sourceStride, len);
341  break;
342  default:
343  wxASSERT(false); // unknown dither algorithm
344  }
345  }
346 }
#define FROM_INT24(ptr)
Definition: Dither.cpp:138
float TriangleDither(float sample)
Definition: Dither.cpp:363
float NoDither(float sample)
Definition: Dither.cpp:351
#define DITHER(dither, dst, dstFormat, dstStride, src, srcFormat, srcStride, len)
Definition: Dither.cpp:196
float RectangleDither(float sample)
Definition: Dither.cpp:357
#define FROM_INT16(ptr)
Definition: Dither.cpp:137
float ShapedDither(float sample)
Definition: Dither.cpp:373
void Reset()
Reset state of the dither.
Definition: Dither.cpp:213
float Dither::NoDither ( float  sample)
inlineprivate

Definition at line 351 of file Dither.cpp.

Referenced by Apply().

352 {
353  return sample;
354 }
float Dither::RectangleDither ( float  sample)
inlineprivate

Definition at line 357 of file Dither.cpp.

References DITHER_NOISE.

Referenced by Apply().

358 {
359  return sample - DITHER_NOISE;
360 }
#define DITHER_NOISE
Definition: Dither.cpp:64
void Dither::Reset ( )

Reset state of the dither.

Definition at line 213 of file Dither.cpp.

References BUF_SIZE, mBuffer, mPhase, and mTriangleState.

Referenced by Apply(), and Dither().

214 {
215  mTriangleState = 0;
216  mPhase = 0;
217  memset(mBuffer, 0, sizeof(float) * BUF_SIZE);
218 }
static const int BUF_SIZE
Definition: Dither.h:47
float mBuffer[8]
Definition: Dither.h:54
int mPhase
Definition: Dither.h:52
float mTriangleState
Definition: Dither.h:53
float Dither::ShapedDither ( float  sample)
inlineprivate

Definition at line 373 of file Dither.cpp.

References BUF_MASK, DITHER_NOISE, lrintf, mBuffer, mPhase, and SHAPED_BS.

Referenced by Apply().

374 {
375  // Generate triangular dither, +-1 LSB, flat psd
376  float r = DITHER_NOISE + DITHER_NOISE;
377  if(sample != sample) // test for NaN
378  sample = 0; // and do the best we can with it
379 
380  // Run FIR
381  float xe = sample + mBuffer[mPhase] * SHAPED_BS[0]
382  + mBuffer[(mPhase - 1) & BUF_MASK] * SHAPED_BS[1]
383  + mBuffer[(mPhase - 2) & BUF_MASK] * SHAPED_BS[2]
384  + mBuffer[(mPhase - 3) & BUF_MASK] * SHAPED_BS[3]
385  + mBuffer[(mPhase - 4) & BUF_MASK] * SHAPED_BS[4];
386 
387  // Accumulate FIR and triangular noise
388  float result = xe + r;
389 
390  // Roll buffer and store last error
391  mPhase = (mPhase + 1) & BUF_MASK;
392  mBuffer[mPhase] = xe - lrintf(result);
393 
394  return result;
395 }
#define DITHER_NOISE
Definition: Dither.cpp:64
static const int BUF_MASK
Definition: Dither.h:48
float mBuffer[8]
Definition: Dither.h:54
int mPhase
Definition: Dither.h:52
#define lrintf(flt)
Definition: float_cast.h:137
static const float SHAPED_BS[]
Definition: Dither.h:49
float Dither::TriangleDither ( float  sample)
inlineprivate

Definition at line 363 of file Dither.cpp.

References DITHER_NOISE, and mTriangleState.

Referenced by Apply().

364 {
365  float r = DITHER_NOISE;
366  float result = sample + r - mTriangleState;
367  mTriangleState = r;
368 
369  return result;
370 }
#define DITHER_NOISE
Definition: Dither.cpp:64
float mTriangleState
Definition: Dither.h:53

Member Data Documentation

const int Dither::BUF_MASK = 7
staticprivate

Definition at line 48 of file Dither.h.

Referenced by ShapedDither().

const int Dither::BUF_SIZE = 8
staticprivate

Definition at line 47 of file Dither.h.

Referenced by Reset().

float Dither::mBuffer[8]
private

Definition at line 54 of file Dither.h.

Referenced by Reset(), and ShapedDither().

int Dither::mPhase
private

Definition at line 52 of file Dither.h.

Referenced by Reset(), and ShapedDither().

float Dither::mTriangleState
private

Definition at line 53 of file Dither.h.

Referenced by Reset(), and TriangleDither().

const float Dither::SHAPED_BS = { 2.033f, -2.165f, 1.959f, -1.590f, 0.6149f }
staticprivate

Definition at line 49 of file Dither.h.

Referenced by ShapedDither().


The documentation for this class was generated from the following files: