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

File libs_libmyth-preamp-patch-ticket-4804, 7.5 KB (added by Erik Hovland <erik@…>, 14 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;