Ticket #4804: libs_libmyth-preamp-patch-ticket-4804

File libs_libmyth-preamp-patch-ticket-4804, 7.5 KB (added by Erik Hovland <erik@…>, 16 years ago)

Same patch as before but against trunk as of 2010-02-03

Line 
1Ticket 4804 is an enhancement to MythTV to provide a pre-amp feature. This is
2
3From: Erik Hovland <erik@hovland.org>
4
5the first step towards having native ReplayGain support in MythMusic.
6---
7
8 mythtv/libs/libmyth/audiooutput.h | 15 ++++
9 mythtv/libs/libmyth/audiooutputbase.cpp | 120 +++++++++++++++++++++++++++++++
10 mythtv/libs/libmyth/audiooutputbase.h | 22 +++++-
11 3 files changed, 155 insertions(+), 2 deletions(-)
12
13
14diff --git a/mythtv/libs/libmyth/audiooutput.h b/mythtv/libs/libmyth/audiooutput.h
15index e89147c..e3014c4 100644
16--- a/mythtv/libs/libmyth/audiooutput.h
17+++ b/mythtv/libs/libmyth/audiooutput.h
18@@ -33,6 +33,21 @@ class MPUBLIC AudioOutput : public VolumeBase, public OutputListeners
19 virtual void SetStretchFactor(float factor);
20 virtual float GetStretchFactor(void) const { return 1.0f; }
21
22+ // For software pre-amplification.
23+ virtual bool IsPreAmpEnabled() const { return false; }
24+ virtual void SetPreAmp(bool enabled) { return; }
25+ virtual void EnablePreAmp() { return; }
26+ virtual void DisablePreAmp() { return; }
27+ virtual void SetPreAmpGain(float gain) { return; }
28+ virtual void SetPreAmpFactor(float factor) { return; }
29+ virtual float GetPreAmpGain() const { return 0.0; }
30+ virtual float GetPreAmpFactor() const { return 1.0; }
31+ virtual void ResetClippingMonitor() { return; }
32+ virtual bool HasClippingOccurred() const { return false; }
33+ virtual float GetMaxOutput() const { return 1.0; }
34+ virtual float GetMaxClipFreePreAmpGain() const { return 0.0; }
35+ virtual float GetMaxClipFreePreAmpFactor() const { return 1.0; }
36+
37 // do AddSamples calls block?
38 virtual void SetBlocking(bool blocking) = 0;
39
40diff --git a/mythtv/libs/libmyth/audiooutputbase.cpp b/mythtv/libs/libmyth/audiooutputbase.cpp
41index 6db02f2..c71d2ad 100644
42--- a/mythtv/libs/libmyth/audiooutputbase.cpp
43+++ b/mythtv/libs/libmyth/audiooutputbase.cpp
44@@ -44,6 +44,9 @@ AudioOutputBase::AudioOutputBase(const AudioSettings &settings) :
45 need_resampler(false),
46
47 src_ctx(NULL),
48+
49+ pre_amp_enabled(false), pre_amp_factor(1.0),
50+ pre_amp_max_output(0.0),
51
52 pSoundStretch(NULL),
53 encoder(NULL),
54@@ -790,6 +793,36 @@ bool AudioOutputBase::AddSamples(char *buffers[], int samples,
55 return true;
56 }
57
58+#define __APPLY_PRE_AMP(TYPE,MIN,MAX) \
59+{ \
60+ TYPE *buf = (TYPE *)buffer; \
61+ for ( int i = 0; i < samples; ++i ) \
62+ { \
63+ float f = (float)buf[i] / (float)MAX; \
64+ f *= pre_amp_factor; \
65+ float a = abs(f); \
66+ if ( a > pre_amp_max_output ) pre_amp_max_output = a; \
67+ if ( f >= 1.0 ) buf[i] = MAX; \
68+ else if ( f <= -1.0 ) buf[i] = MIN; \
69+ else buf[i] = (TYPE)round(f*MAX); \
70+ } \
71+}
72+
73+void AudioOutputBase::ApplyPreAmp(void *buffer, int samples, int sample_bytes)
74+{
75+ if ( !pre_amp_enabled ) return;
76+ // NOTE: This only handles 1, 2 or 4 byte samples.
77+ if ( sample_bytes == 4 )
78+ __APPLY_PRE_AMP(int,INT_MIN,INT_MAX)
79+ else if ( sample_bytes == 2 )
80+ __APPLY_PRE_AMP(short,SHRT_MIN,SHRT_MAX)
81+ else if ( sample_bytes == 1 )
82+ __APPLY_PRE_AMP(char,CHAR_MIN,CHAR_MAX)
83+
84+ return;
85+}
86+#undef __APPLY_PRE_AMP
87+
88 bool AudioOutputBase::AddSamples(char *buffer, int samples, long long timecode)
89 {
90 // NOTE: This function is not threadsafe
91@@ -928,6 +961,17 @@ void AudioOutputBase::_AddSamples(void *buffer, bool interleaved, int samples,
92 int audio_bytes = audio_bits / 8;
93 int org_waud = waud;
94
95+ if ( interleaved )
96+ // Apply to the single buffer if we're interleaved.
97+ ApplyPreAmp(buffer,samples*source_audio_channels,audio_bytes);
98+ else
99+ {
100+ // Otherwise, apply to each channel individually.
101+ void **bufs = (void**)buffer;
102+ for ( int i = 0; i < source_audio_channels; ++i )
103+ ApplyPreAmp(bufs[i],samples,audio_bytes);
104+ }
105+
106 int afree = audiofree(false);
107
108 int abps = (encoder) ?
109@@ -1408,5 +1452,79 @@ int AudioOutputBase::readOutputData(unsigned char*, int)
110 return 0;
111 }
112
113-/* vim: set expandtab tabstop=4 shiftwidth=4: */
114+bool AudioOutputBase::IsPreAmpEnabled() const
115+{
116+ return pre_amp_enabled;
117+}
118+
119+void AudioOutputBase::SetPreAmp(bool enabled)
120+{
121+ pre_amp_enabled = enabled;
122+ return;
123+}
124+
125+void AudioOutputBase::EnablePreAmp()
126+{
127+ pre_amp_enabled = true;
128+ return;
129+}
130+
131+void AudioOutputBase::DisablePreAmp()
132+{
133+ pre_amp_enabled = false;
134+ return;
135+}
136+
137+void AudioOutputBase::SetPreAmpGain(float gain)
138+{
139+ pre_amp_factor = pow(10.0,gain/20.0);
140+ return;
141+}
142
143+void AudioOutputBase::SetPreAmpFactor(float factor)
144+{
145+ if ( factor >= 0 ) pre_amp_factor = factor;
146+ return;
147+}
148+
149+float AudioOutputBase::GetPreAmpGain() const
150+{
151+ if ( pre_amp_factor <= 0 ) return -1.0*numeric_limits<float>::max();
152+ return 20.0*log(pre_amp_factor)/log(10.0);
153+}
154+
155+float AudioOutputBase::GetPreAmpFactor() const
156+{
157+ return pre_amp_factor;
158+}
159+
160+void AudioOutputBase::ResetClippingMonitor()
161+{
162+ pre_amp_max_output = 0.0;
163+ return;
164+}
165+
166+bool AudioOutputBase::HasClippingOccurred() const
167+{
168+ return pre_amp_max_output > 1.0;
169+}
170+
171+float AudioOutputBase::GetMaxOutput() const
172+{
173+ return pre_amp_max_output;
174+}
175+
176+float AudioOutputBase::GetMaxClipFreePreAmpGain() const
177+{
178+ float max_factor = GetMaxClipFreePreAmpFactor();
179+ if ( max_factor <= 0 ) return -1.0*numeric_limits<float>::max();
180+ return 20.0*log(max_factor)/log(10.0);
181+}
182+
183+float AudioOutputBase::GetMaxClipFreePreAmpFactor() const
184+{
185+ if ( pre_amp_max_output == 0 ) return numeric_limits<float>::max();
186+ return pre_amp_factor / pre_amp_max_output;
187+}
188+
189+/* vim: set expandtab tabstop=4 shiftwidth=4: */
190diff --git a/mythtv/libs/libmyth/audiooutputbase.h b/mythtv/libs/libmyth/audiooutputbase.h
191index 8d9e86b..1732d97 100644
192--- a/mythtv/libs/libmyth/audiooutputbase.h
193+++ b/mythtv/libs/libmyth/audiooutputbase.h
194@@ -71,8 +71,22 @@ class AudioOutputBase : public AudioOutput, public QThread
195
196 virtual void GetBufferStatus(uint &fill, uint &total);
197
198- // Only really used by the AudioOutputNULL object
199+ // For software pre-amplification.
200+ virtual bool IsPreAmpEnabled() const;
201+ virtual void SetPreAmp(bool enabled);
202+ virtual void EnablePreAmp();
203+ virtual void DisablePreAmp();
204+ virtual void SetPreAmpGain(float gain);
205+ virtual void SetPreAmpFactor(float factor);
206+ virtual float GetPreAmpGain() const;
207+ virtual float GetPreAmpFactor() const;
208+ virtual void ResetClippingMonitor();
209+ virtual bool HasClippingOccurred() const;
210+ virtual float GetMaxOutput() const;
211+ virtual float GetMaxClipFreePreAmpGain() const;
212+ virtual float GetMaxClipFreePreAmpFactor() const;
213
214+ // Only really used by the AudioOutputNULL object
215 virtual void bufferOutputData(bool y){ buffer_output_data_for_use = y; }
216 virtual int readOutputData(unsigned char *read_buffer, int max_length);
217
218@@ -100,6 +114,7 @@ class AudioOutputBase : public AudioOutput, public QThread
219
220 int GetAudioData(unsigned char *buffer, int buf_size, bool fill_buffer);
221
222+ void ApplyPreAmp(void *buffer, int samples, int sample_bytes);
223 void _AddSamples(void *buffer, bool interleaved, int samples, long long timecode);
224
225 void OutputAudioLoop(void);
226@@ -165,6 +180,11 @@ class AudioOutputBase : public AudioOutput, public QThread
227 bool need_resampler;
228 SRC_STATE *src_ctx;
229
230+ // pre-amplification
231+ bool pre_amp_enabled;
232+ float pre_amp_factor;
233+ float pre_amp_max_output;
234+
235 // timestretch
236 soundtouch::SoundTouch *pSoundStretch;
237 AudioOutputDigitalEncoder *encoder;