1
/***************************************************************************
2
audioeng_6dbpress.cpp - description
4
Derived from audactity compressor
5
see http://audacity.sf.net
6
***************************************************************************/
7
/**********************************************************************
9
Audacity: A Digital Audio Editor
15
Steve Jolly made it inherit from EffectSimpleMono.
16
GUI added and implementation improved by Dominic Mazzoni, 5/11/2003.
18
**********************************************************************/
21
/***************************************************************************
23
* This program is free software; you can redistribute it and/or modify *
24
* it under the terms of the GNU General Public License as published by *
25
* the Free Software Foundation; either version 2 of the License, or *
26
* (at your option) any later version. *
28
***************************************************************************/
33
#include <ADM_assert.h>
41
//#include "aviaudio.hxx"
42
#include "audioprocess.hxx"
43
//#include "../toolkit.hxx"
48
AVDMProcessAudio_Compress::AVDMProcessAudio_Compress(AVDMGenericAudioStream * instream,DRCparam *p):AVDMBufferedAudioStream
52
// nothing special here...
53
double ramp, coef, off;
55
_wavheader = new WAVHeader;
57
memcpy(_wavheader, _instream->getInfo(), sizeof(WAVHeader));
58
_wavheader->encoding = WAV_PCM;
59
_wavheader->byterate =
60
_wavheader->channels * _wavheader->frequency * 2;
61
_instream->goToTime(0);
62
memcpy(&_param,p,sizeof(_param));
67
strcpy(_name, "PROC:PRESS");
68
mCircleSize=DRC_WINDOW;
74
void AVDMProcessAudio_Compress::drc_cleanup(void)
76
double mCurRate=(double)_wavheader->frequency;
79
for(int j=0; j<mCircleSize; j++) {
81
mLevelCircle[j] = _param.mFloor;
86
mGainDB = ((_param.mThresholdDB*-0.7) * (1 - 1/_param.mRatio));
90
mThreshold = pow(10.0, _param.mThresholdDB/10); // factor of 10 because it's power
93
mGain = pow(10.0, mGainDB/20); // factor of 20 because it's amplitude
97
mAttackFactor = exp(-log(_param.mFloor) / (mCurRate * _param.mAttackTime + 0.5));
98
mDecayFactor = exp(log(_param.mFloor) / (mCurRate * _param.mDecayTime + 0.5));
102
memset(mCircle,0,sizeof(mCircle));
103
memset(follow,0,sizeof(follow));
104
memset(mLevelCircle,0,sizeof(mLevelCircle));
108
AVDMProcessAudio_Compress::~AVDMProcessAudio_Compress()
114
//_____________________________________________
115
uint32_t AVDMProcessAudio_Compress::grab(uint8_t * _outbuff)
120
uint8_t *incoming=(uint8_t *)_buffer;
122
len = _instream->read(ONE_CHUNK, (uint8_t *) (incoming));
123
//printf("\n grabbing :%lu-->%lu\n",ms100,rdall);
125
if (len != ONE_CHUNK)
127
printf("\n not enough...\n");
129
return MINUS_ONE; // we could not get a single byte ! End of stream
130
// Else fillout with 0
131
for(int i=len;i<ONE_CHUNK;i++)
134
// Convert to float between 1&-1
135
for(i=0;i<ONE_CHUNK/2;i++)
137
value[i]=(double)_buffer[i]/32767.;
141
int16_t *ofer=(int16_t *)_outbuff; // Out
142
len=ONE_CHUNK/2;// 16 bits / sample
145
if (mLastLevel == 0.0) {
146
int preSeed = mCircleSize;
149
for(i=0; i<preSeed; i++)
153
for (i = 0; i < len; i++) {
154
Follow(value[i], &follow[i], i);
157
for (i = 0; i < len; i++) {
158
ofer[i] =(int16_t) (32767.*DoCompression(value[i], follow[i]));
164
double AVDMProcessAudio_Compress::AvgCircle(double value)
168
// Calculate current level from root-mean-squared of
169
// circular buffer ("RMS")
170
mRMSSum -= mCircle[mCirclePos];
171
mCircle[mCirclePos] = value*value;
172
mRMSSum += mCircle[mCirclePos];
173
level = sqrt(mRMSSum/mCircleSize);
174
mLevelCircle[mCirclePos] = level;
175
mCirclePos = (mCirclePos+1)%mCircleSize;
179
void AVDMProcessAudio_Compress::Follow(double x, double *outEnv, int maxBack)
183
"Follow"ing algorithm by Roger B. Dannenberg, taken from
184
Nyquist. His description follows. -DMM
186
Description: this is a sophisticated envelope follower.
187
The input is an envelope, e.g. something produced with
188
the AVG function. The purpose of this function is to
189
generate a smooth envelope that is generally not less
190
than the input signal. In other words, we want to "ride"
191
the peaks of the signal with a smooth function. The
192
algorithm is as follows: keep a current output value
193
(called the "value"). The value is allowed to increase
194
by at most rise_factor and decrease by at most fall_factor.
195
Therefore, the next value should be between
196
value * rise_factor and value * fall_factor. If the input
197
is in this range, then the next value is simply the input.
198
If the input is less than value * fall_factor, then the
199
next value is just value * fall_factor, which will be greater
200
than the input signal. If the input is greater than value *
201
rise_factor, then we compute a rising envelope that meets
202
the input value by working bacwards in time, changing the
203
previous values to input / rise_factor, input / rise_factor^2,
204
input / rise_factor^3, etc. until this new envelope intersects
205
the previously computed values. There is only a limited buffer
206
in which we can work backwards, so if the new envelope does not
207
intersect the old one, then make yet another pass, this time
208
from the oldest buffered value forward, increasing on each
209
sample by rise_factor to produce a maximal envelope. This will
210
still be less than the input.
212
The value has a lower limit of floor to make sure value has a
213
reasonable positive value from which to begin an attack.
216
float level = AvgCircle(x);
217
float high = mLastLevel * mAttackFactor;
218
float low = mLastLevel * mDecayFactor;
220
if (low < _param.mFloor)
225
else if (level < high)
229
double attackInverse = 1.0 / mAttackFactor;
230
double temp = level * attackInverse;
233
if (backtrack > maxBack)
236
double *ptr = &outEnv[-1];
239
for(i=0; i<backtrack-2; i++) {
242
temp *= attackInverse;
250
if (!ok && backtrack>1 && (*ptr < temp)) {
252
for (i = 0; i < backtrack-1; i++) {
254
temp *= mAttackFactor;
262
mLastLevel = *outEnv;
265
float AVDMProcessAudio_Compress::DoCompression(float value, double env)
270
if (env > mThreshold)
271
mult = mGain * pow(mThreshold/env, 1.0/_param.mRatio);