MythTV master
audiooutputdownmix.cpp
Go to the documentation of this file.
1/*
2Copyright (C) 2010-2011 Jean-Yves Avenard
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
16Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17*/
18
19#include "audiooutputbase.h"
20#include "audiooutputdownmix.h"
21
22#include <cstring>
23
25
26#define LOC QString("Downmixer: ")
27
28/*
29 SMPTE channel layout
30 DUAL-MONO L R
31 DUAL-MONO-LFE L R LFE
32 MONO M
33 MONO-LFE M LFE
34 STEREO L R
35 STEREO-LFE L R LFE
36 3F L R C
37 3F-LFE L R C LFE
38 2F1 L R S
39 2F1-LFE L R LFE S
40 3F1 L R C S
41 3F1-LFE L R C LFE S
42 2F2 L R LS RS
43 2F2-LFE L R LFE LS RS
44 3F2 L R C LS RS
45 3F2-LFE L R C LFE LS RS
46 3F3R-LFE L R C LFE BC LS RS
47 3F4-LFE L R C LFE Rls Rrs LS RS
48 */
49
50static const float m6db = 0.5;
51static const float m3db = 0.7071067811865476F; // 3dB = SQRT(2)
52static const float mm3db = -0.7071067811865476F; // -3dB = SQRT(1/2)
53static const float msqrt_1_3 = -0.577350269189626F; // -SQRT(1/3)
54static const float sqrt_2_3 = 0.816496580927726F; // SQRT(2/3)
55static const float sqrt_2_3by3db = 0.577350269189626F; // SQRT(2/3)*-3dB = SQRT(2/3)*SQRT(1/2)=SQRT(1/3)
56static const float msqrt_1_3bym3db = 0.408248290463863F; // -SQRT(1/3)*-3dB = -SQRT(1/3)*SQRT(1/2) = -SQRT(1/6)
57
58using two_speaker_ratio = std::array<float,2>;
59using two_speaker_set = std::array<two_speaker_ratio,8>;
60static const std::array<two_speaker_set,8> stereo_matrix
61{{
62//1F L R
63 {{
64 { 1, 1 }, // M
65 }},
66
67//2F L R
68 {{
69 { 1, 0 }, // L
70 { 0, 1 }, // R
71 }},
72
73//3F L R
74 {{
75 { 1, 0 }, // L
76 { 0, 1 }, // R
77 { 1, 1 }, // C
78 }},
79
80//3F1R L R
81 {{
82 { 1, 0 }, // L
83 { 0, 1 }, // R
84 { m3db, m3db }, // C
85 { mm3db, m3db }, // S
86 }},
87
88//3F2R L R
89 {{
90 { 1, 0 }, // L
91 { 0, 1 }, // R
92 { m3db, m3db }, // C
93 { sqrt_2_3, msqrt_1_3 }, // LS
94 { msqrt_1_3, sqrt_2_3 }, // RS
95 }},
96
97//3F2R.1 L R
98 {{
99 { 1, 0 }, // L
100 { 0, 1 }, // R
101 { m3db, m3db }, // C
102 { 0, 0 }, // LFE
103 { sqrt_2_3, msqrt_1_3 }, // LS
104 { msqrt_1_3, sqrt_2_3 }, // RS
105 }},
106
107// 3F3R.1 L R
108 {{
109 { 1, 0 }, // L
110 { 0, 1 }, // R
111 { m3db, m3db }, // C
112 { 0, 0 }, // LFE
113 { m6db, m6db }, // Cs
114 { sqrt_2_3, msqrt_1_3 }, // LS
115 { msqrt_1_3, sqrt_2_3 }, // RS
116 }},
117
118// 3F4R.1 L R
119 {{
120 { 1, 0 }, // L
121 { 0, 1 }, // R
122 { m3db, m3db }, // C
123 { 0, 0 }, // LFE
124 { sqrt_2_3by3db, msqrt_1_3bym3db }, // Rls
125 { msqrt_1_3bym3db, sqrt_2_3by3db }, // Rrs
128 }}
129}};
130
131using six_speaker_ratio = std::array<float,6>;
132using six_speaker_set = std::array<six_speaker_ratio,8>;
133static const std::array<six_speaker_set,3> s51_matrix
134{{
135 // 3F2R.1 in -> 3F2R.1 out
136 // L R C LFE LS RS
137 {{
138 { 1, 0, 0, 0, 0, 0 }, // L
139 { 0, 1, 0, 0, 0, 0 }, // R
140 { 0, 0, 1, 0, 0, 0 }, // C
141 { 0, 0, 0, 1, 0, 0 }, // LFE
142 { 0, 0, 0, 0, 1, 0 }, // LS
143 { 0, 0, 0, 0, 0, 1 }, // RS
144 }},
145 // 3F3R.1 in -> 3F2R.1 out
146 // Used coefficient found at http://www.yamahaproaudio.com/training/self_training/data/smqr_en.pdf
147 // L R C LFE LS RS
148 {{
149 { 1, 0, 0, 0, 0, 0 }, // L
150 { 0, 1, 0, 0, 0, 0 }, // R
151 { 0, 0, 1, 0, 0, 0 }, // C
152 { 0, 0, 0, 1, 0, 0 }, // LFE
153 { 0, 0, 0, 0, m3db, m3db }, // Cs
154 { 0, 0, 0, 0, 1, 0 }, // LS
155 { 0, 0, 0, 0, 0, 1 }, // RS
156 }},
157 // 3F4R.1 -> 3F2R.1 out
158 // L R C LFE LS RS
159 {{
160 { 1, 0, 0, 0, 0, 0 }, // L
161 { 0, 1, 0, 0, 0, 0 }, // R
162 { 0, 0, 1, 0, 0, 0 }, // C
163 { 0, 0, 0, 1, 0, 0 }, // LFE
164 { 0, 0, 0, 0, m3db, 0 }, // Rls
165 { 0, 0, 0, 0, 0, m3db }, // Rrs
166 { 0, 0, 0, 0, m3db, 0 }, // LS
167 { 0, 0, 0, 0, 0, m3db }, // RS
168 }}
169}};
170
171int AudioOutputDownmix::DownmixFrames(int channels_in, int channels_out,
172 float *dst, const float *src, int frames)
173{
174 if (channels_in < channels_out)
175 return -1;
176
177 //LOG(VB_AUDIO, LOG_INFO, LOC + LOC + QString("Downmixing %1 frames (in:%2 out:%3)")
178 // .arg(frames).arg(channels_in).arg(channels_out));
179 if (channels_out == 2)
180 {
181 int index = channels_in - 1;
182 for (int n=0; n < frames; n++)
183 {
184 for (int i=0; i < channels_out; i++)
185 {
186 float tmp = 0.0F;
187 for (int j=0; j < channels_in; j++)
188 tmp += src[j] * stereo_matrix[index][j][i];
189 *dst++ = tmp;
190 }
191 src += channels_in;
192 }
193 }
194 else if (channels_out == 6)
195 {
196 int index = channels_in - 6;
197 for (int n=0; n < frames; n++)
198 {
199 for (int i=0; i < channels_out; i++)
200 {
201 float tmp = 0.0F;
202 for (int j=0; j < channels_in; j++)
203 tmp += src[j] * s51_matrix[index][j][i];
204 *dst++ = tmp;
205 }
206 src += channels_in;
207 }
208 }
209 else
210 {
211 return -1;
212 }
213
214 return frames;
215}
static const std::array< six_speaker_set, 3 > s51_matrix
static const float msqrt_1_3bym3db
std::array< float, 2 > two_speaker_ratio
static const float sqrt_2_3by3db
static const float sqrt_2_3
std::array< float, 6 > six_speaker_ratio
static const float m3db
static const float mm3db
static const std::array< two_speaker_set, 8 > stereo_matrix
std::array< six_speaker_ratio, 8 > six_speaker_set
static const float m6db
std::array< two_speaker_ratio, 8 > two_speaker_set
static const float msqrt_1_3
static int DownmixFrames(int channels_in, int channels_out, float *dst, const float *src, int frames)
static guint32 * tmp
Definition: goom_core.cpp:26