-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathDither.cpp
395 lines (339 loc) · 14.3 KB
/
Dither.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
/**********************************************************************
Audacity: A Digital Audio Editor
Dither.cpp
Steve Harris
Markus Meyer
*******************************************************************//*!
\class Dither
\brief
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:
- No dithering at all
- Rectangle dithering
- Triangle dithering
- Noise-shaped dithering
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.
*//*******************************************************************/
// Erik de Castro Lopo's header file that
// makes sure that we have lrint and lrintf
// (Note: this file should be included first)
#include "float_cast.h"
#include <stdlib.h>
#include <math.h>
#include <string.h>
//#include <sys/types.h>
//#include <memory.h>
//#include <assert.h>
#include <wx/defs.h>
#include "Dither.h"
//////////////////////////////////////////////////////////////////////////
// Constants for the noise shaping buffer
const int Dither::BUF_MASK = 7;
const int Dither::BUF_SIZE = 8;
// Lipshitz's minimally audible FIR
const float Dither::SHAPED_BS[] = { 2.033f, -2.165f, 1.959f, -1.590f, 0.6149f };
// This is supposed to produce white noise and no dc
#define DITHER_NOISE (rand() / (float)RAND_MAX - 0.5f)
// The following is a rather ugly, but fast implementation
// of a dither loop. The macro "DITHER" is expanded to an implementation
// of a dithering algorithm, which contains no branches in the inner loop
// except the branches for clipping the sample, and therefore should
// be quite fast.
#if 0
// To assist in understanding what the macros are doing, here's an example of what
// the result would be for Shaped dither:
//
// DITHER(ShapedDither, dest, destFormat, destStride, source, sourceFormat, sourceStride, len);
do {
if (sourceFormat == int24Sample && destFormat == int16Sample)
do {
char *d, *s;
unsigned int i;
int x;
for (d = (char*)dest, s = (char*)source, i = 0; i < len; i++, d += (int16Sample >> 16) * destStride, s += (int24Sample >> 16) * sourceStride)
do {
x = lrintf((ShapedDither((((*(( int*)(s)) / float(1<<23))) * float(1<<15)))));
if (x>(32767))
*((short*)((((d)))))=(32767);
else if (x<(-32768))
*((short*)((((d)))))=(-32768);
else *((short*)((((d)))))=(short)x;
} while (0);
} while (0);
else if (sourceFormat == floatSample && destFormat == int16Sample)
do {
char *d, *s;
unsigned int i;
int x;
for (d = (char*)dest, s = (char*)source, i = 0; i < len; i++, d += (int16Sample >> 16) * destStride, s += (floatSample >> 16) * sourceStride)
do {
x = lrintf((ShapedDither((((*((float*)(s)) > 1.0 ? 1.0 : *((float*)(s)) < -1.0 ? -1.0 : *((float*)(s)))) * float(1<<15)))));
if (x>(32767))
*((short*)((((d)))))=(32767);
else if (x<(-32768))
*((short*)((((d)))))=(-32768);
else *((short*)((((d)))))=(short)x;
} while (0);
} while (0);
else if (sourceFormat == floatSample && destFormat == int24Sample)
do {
char *d, *s;
unsigned int i;
int x;
for (d = (char*)dest, s = (char*)source, i = 0; i < len; i++, d += (int24Sample >> 16) * destStride, s += (floatSample >> 16) * sourceStride)
do {
x = lrintf((ShapedDither((((*((float*)(s)) > 1.0 ? 1.0 : *((float*)(s)) < -1.0 ? -1.0 : *((float*)(s)))) * float(1<<23)))));
if (x>(8388607))
*((int*)((((d)))))=(8388607);
else if (x<(-8388608))
*((int*)((((d)))))=(-8388608);
else *((int*)((((d)))))=(int)x;
} while (0);
} while (0);
else {
if ( false )
;
else wxOnAssert(L"c:\\users\\yam\\documents\\audacity\\mixer\\n\\audacity\\src\\dither.cpp", 348, __FUNCTION__ , L"false", 0);
}
} while (0);
#endif
// Defines for sample conversion
#define CONVERT_DIV16 float(1<<15)
#define CONVERT_DIV24 float(1<<23)
// Dereference sample pointer and convert to float sample
#define FROM_INT16(ptr) (*((short*)(ptr)) / CONVERT_DIV16)
#define FROM_INT24(ptr) (*(( int*)(ptr)) / CONVERT_DIV24)
// For float, we internally allow values greater than 1.0, which
// would blow up the dithering to int values. FROM_FLOAT is
// only used to dither to int, so clip here.
#define FROM_FLOAT(ptr) (*((float*)(ptr)) > 1.0 ? 1.0 : \
*((float*)(ptr)) < -1.0 ? -1.0 : \
*((float*)(ptr)))
// Promote sample to range of specified type, keep it float, though
#define PROMOTE_TO_INT16(sample) ((sample) * CONVERT_DIV16)
#define PROMOTE_TO_INT24(sample) ((sample) * CONVERT_DIV24)
// Store float sample 'sample' into pointer 'ptr', clip it, if necessary
// Note: This assumes, a variable 'x' of type int is valid which is
// used by this macro.
#define IMPLEMENT_STORE(ptr, sample, ptr_type, min_bound, max_bound) \
do { \
x = lrintf(sample); \
if (x>(max_bound)) *((ptr_type*)(ptr))=(max_bound); \
else if (x<(min_bound)) *((ptr_type*)(ptr))=(min_bound); \
else *((ptr_type*)(ptr))=(ptr_type)x; } while (0)
#define STORE_INT16(ptr, sample) IMPLEMENT_STORE((ptr), (sample), short, -32768, 32767)
#define STORE_INT24(ptr, sample) IMPLEMENT_STORE((ptr), (sample), int, -8388608, 8388607)
// Dither single float 'sample' and store it in pointer 'dst', using 'dither' as algorithm
#define DITHER_TO_INT16(dither, dst, sample) STORE_INT16((dst), dither(PROMOTE_TO_INT16(sample)))
#define DITHER_TO_INT24(dither, dst, sample) STORE_INT24((dst), dither(PROMOTE_TO_INT24(sample)))
// Implement one single dither step
#define DITHER_STEP(dither, store, load, dst, src) \
store(dither, (dst), load(src))
// Implement a dithering loop
// Note: The variable 'x' is needed for the STORE_... macros
#define DITHER_LOOP(dither, store, load, dst, dstFormat, dstStride, src, srcFormat, srcStride, len) \
do { \
char *d, *s; \
unsigned int i; \
int x; \
for (d = (char*)dst, s = (char*)src, i = 0; \
i < len; \
i++, d += SAMPLE_SIZE(dstFormat) * dstStride, \
s += SAMPLE_SIZE(srcFormat) * srcStride) \
DITHER_STEP(dither, store, load, d, s); \
} while (0)
// Shortcuts to dithering loops
#define DITHER_INT24_TO_INT16(dither, dst, dstStride, src, srcStride, len) \
DITHER_LOOP(dither, DITHER_TO_INT16, FROM_INT24, dst, int16Sample, dstStride, src, int24Sample, srcStride, len)
#define DITHER_FLOAT_TO_INT16(dither, dst, dstStride, src, srcStride, len) \
DITHER_LOOP(dither, DITHER_TO_INT16, FROM_FLOAT, dst, int16Sample, dstStride, src, floatSample, srcStride, len)
#define DITHER_FLOAT_TO_INT24(dither, dst, dstStride, src, srcStride, len) \
DITHER_LOOP(dither, DITHER_TO_INT24, FROM_FLOAT, dst, int24Sample, dstStride, src, floatSample, srcStride, len)
// Implement a dither. There are only 3 cases where we must dither,
// in all other cases, no dithering is necessary.
#define DITHER(dither, dst, dstFormat, dstStride, src, srcFormat, srcStride, len) \
do { if (srcFormat == int24Sample && dstFormat == int16Sample) \
DITHER_INT24_TO_INT16(dither, dst, dstStride, src, srcStride, len); \
else if (srcFormat == floatSample && dstFormat == int16Sample) \
DITHER_FLOAT_TO_INT16(dither, dst, dstStride, src, srcStride, len); \
else if (srcFormat == floatSample && dstFormat == int24Sample) \
DITHER_FLOAT_TO_INT24(dither, dst, dstStride, src, srcStride, len); \
else { wxASSERT(false); } \
} while (0)
Dither::Dither()
{
// On startup, initialize dither by resetting values
Reset();
}
void Dither::Reset()
{
mTriangleState = 0;
mPhase = 0;
memset(mBuffer, 0, sizeof(float) * BUF_SIZE);
}
// This only decides if we must dither at all, the dithers
// are all implemented using macros.
//
// "source" and "dest" can contain either interleaved or non-interleaved
// samples. They do not have to be the same...one can be interleaved while
// the otner non-interleaved.
//
// The "len" argument specifies the number of samples to process.
//
// If either stride value equals 1 then the corresponding buffer contains
// non-interleaved samples.
//
// If either stride value is greater than 1 then the corresponding buffer
// contains interleaved samples and they will be processed by skipping every
// stride number of samples.
void Dither::Apply(enum DitherType ditherType,
const samplePtr source, sampleFormat sourceFormat,
samplePtr dest, sampleFormat destFormat,
unsigned int len,
unsigned int sourceStride /* = 1 */,
unsigned int destStride /* = 1 */)
{
unsigned int i;
// This code is not designed for 16-bit or 64-bit machine
wxASSERT(sizeof(int) == 4);
wxASSERT(sizeof(short) == 2);
// Check parameters
wxASSERT(source);
wxASSERT(dest);
wxASSERT(len >= 0);
wxASSERT(sourceStride > 0);
wxASSERT(destStride > 0);
if (len == 0)
return; // nothing to do
if (destFormat == sourceFormat)
{
// No need to dither, because source and destination
// format are the same. Just copy samples.
if (destStride == 1 && sourceStride == 1)
memcpy(dest, source, len * SAMPLE_SIZE(destFormat));
else
{
if (sourceFormat == floatSample)
{
float* d = (float*)dest;
float* s = (float*)source;
for (i = 0; i < len; i++, d += destStride, s += sourceStride)
*d = *s;
} else
if (sourceFormat == int24Sample)
{
int* d = (int*)dest;
int* s = (int*)source;
for (i = 0; i < len; i++, d += destStride, s += sourceStride)
*d = *s;
} else
if (sourceFormat == int16Sample)
{
short* d = (short*)dest;
short* s = (short*)source;
for (i = 0; i < len; i++, d += destStride, s += sourceStride)
*d = *s;
} else {
wxASSERT(false); // source format unknown
}
}
} else
if (destFormat == floatSample)
{
// No need to dither, just convert samples to float.
// No clipping should be necessary.
float* d = (float*)dest;
if (sourceFormat == int16Sample)
{
short* s = (short*)source;
for (i = 0; i < len; i++, d += destStride, s += sourceStride)
*d = FROM_INT16(s);
} else
if (sourceFormat == int24Sample)
{
int* s = (int*)source;
for (i = 0; i < len; i++, d += destStride, s += sourceStride)
*d = FROM_INT24(s);
} else {
wxASSERT(false); // source format unknown
}
} else
if (destFormat == int24Sample && sourceFormat == int16Sample)
{
// Special case when promoting 16 bit to 24 bit
int* d = (int*)dest;
short* s = (short*)source;
for (i = 0; i < len; i++, d += destStride, s += sourceStride)
*d = ((int)*s) << 8;
} else
{
// We must do dithering
switch (ditherType)
{
case none:
DITHER(NoDither, dest, destFormat, destStride, source, sourceFormat, sourceStride, len);
break;
case rectangle:
DITHER(RectangleDither, dest, destFormat, destStride, source, sourceFormat, sourceStride, len);
break;
case triangle:
Reset(); // reset dither filter for this new conversion
DITHER(TriangleDither, dest, destFormat, destStride, source, sourceFormat, sourceStride, len);
break;
case shaped:
Reset(); // reset dither filter for this new conversion
DITHER(ShapedDither, dest, destFormat, destStride, source, sourceFormat, sourceStride, len);
break;
default:
wxASSERT(false); // unknown dither algorithm
}
}
}
// Dither implementations
// No dither, just return sample
inline float Dither::NoDither(float sample)
{
return sample;
}
// Rectangle dithering, apply one-step noise
inline float Dither::RectangleDither(float sample)
{
return sample - DITHER_NOISE;
}
// Triangle dither - high pass filtered
inline float Dither::TriangleDither(float sample)
{
float r = DITHER_NOISE;
float result = sample + r - mTriangleState;
mTriangleState = r;
return result;
}
// Shaped dither
inline float Dither::ShapedDither(float sample)
{
// Generate triangular dither, +-1 LSB, flat psd
float r = DITHER_NOISE + DITHER_NOISE;
if(sample != sample) // test for NaN
sample = 0; // and do the best we can with it
// Run FIR
float xe = sample + mBuffer[mPhase] * SHAPED_BS[0]
+ mBuffer[(mPhase - 1) & BUF_MASK] * SHAPED_BS[1]
+ mBuffer[(mPhase - 2) & BUF_MASK] * SHAPED_BS[2]
+ mBuffer[(mPhase - 3) & BUF_MASK] * SHAPED_BS[3]
+ mBuffer[(mPhase - 4) & BUF_MASK] * SHAPED_BS[4];
// Accumulate FIR and triangular noise
float result = xe + r;
// Roll buffer and store last error
mPhase = (mPhase + 1) & BUF_MASK;
mBuffer[mPhase] = xe - lrintf(result);
return result;
}