1 /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
6 #include <errno.h>
7 #include <stddef.h>
8 #include <stdlib.h>
9 #include <syslog.h>
10
11 #include "cras_audio_format.h"
12
13
14 /* Table for allowed alternatives when doing channel re-mapping.
15 * When channel_alt[X][Y] is non-zero, it's allowed to map channel
16 * from X to Y. */
17 static const int channel_alt[CRAS_CH_MAX][CRAS_CH_MAX] =
18 {
19 /* FL FR RL RR FC LFE SL SR RC FLC FRC */
20 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* FL */
21 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* FR */
22 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* RL */
23 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* RR */
24 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* FC */
25 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* LFE */
26 { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, /* SL */
27 { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, /* SR */
28 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* RC */
29 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* FLC */
30 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* FRC */
31 };
32
33 /* Create an audio format structure. */
cras_audio_format_create(snd_pcm_format_t format,size_t frame_rate,size_t num_channels)34 struct cras_audio_format *cras_audio_format_create(snd_pcm_format_t format,
35 size_t frame_rate,
36 size_t num_channels)
37 {
38 struct cras_audio_format *fmt;
39 unsigned i;
40
41 fmt = (struct cras_audio_format *)calloc(1, sizeof(*fmt));
42 if (fmt == NULL)
43 return fmt;
44
45 fmt->format = format;
46 fmt->frame_rate = frame_rate;
47 fmt->num_channels = num_channels;
48
49 /* Set a default working channel layout according to num_channels.
50 * Initialize all other channel position to -1(not set)
51 */
52 for (i = 0; i < CRAS_CH_MAX; i++)
53 fmt->channel_layout[i] = (i < num_channels) ? i : -1;
54
55 return fmt;
56 }
57
cras_audio_format_set_channel_layout(struct cras_audio_format * format,const int8_t layout[CRAS_CH_MAX])58 int cras_audio_format_set_channel_layout(struct cras_audio_format *format,
59 const int8_t layout[CRAS_CH_MAX])
60 {
61 int i;
62
63 /* Check that the max channel index should not exceed the
64 * channel count set in format.
65 */
66 for (i = 0; i < CRAS_CH_MAX; i++)
67 if (layout[i] >= (int)format->num_channels)
68 return -EINVAL;
69
70 for (i = 0; i < CRAS_CH_MAX; i++)
71 format->channel_layout[i] = layout[i];
72
73 return 0;
74 }
75
76 /* Destroy an audio format struct created with cras_audio_format_crate. */
cras_audio_format_destroy(struct cras_audio_format * fmt)77 void cras_audio_format_destroy(struct cras_audio_format *fmt)
78 {
79 free(fmt);
80 }
81
cras_channel_conv_matrix_alloc(size_t in_ch,size_t out_ch)82 float** cras_channel_conv_matrix_alloc(size_t in_ch, size_t out_ch)
83 {
84 size_t i;
85 float **p;
86 p = (float **)calloc(out_ch, sizeof(*p));
87 if (p == NULL)
88 return NULL;
89 for (i = 0; i < out_ch; i++) {
90 p[i] = (float *)calloc(in_ch, sizeof(*p[i]));
91 if (p[i] == NULL)
92 goto alloc_err;
93 }
94 return p;
95
96 alloc_err:
97 if (p)
98 cras_channel_conv_matrix_destroy(p, out_ch);
99 return NULL;
100 }
101
cras_channel_conv_matrix_destroy(float ** p,size_t out_ch)102 void cras_channel_conv_matrix_destroy(float **p, size_t out_ch)
103 {
104 size_t i;
105 for (i = 0; i < out_ch; i ++)
106 free(p[i]);
107 free(p);
108 }
109
cras_channel_conv_matrix_create(const struct cras_audio_format * in,const struct cras_audio_format * out)110 float **cras_channel_conv_matrix_create(const struct cras_audio_format *in,
111 const struct cras_audio_format *out)
112 {
113 int i;
114 float **mtx;
115
116 for (i = 0; i < CRAS_CH_MAX; i++) {
117 if (in->channel_layout[i] >= (int)in->num_channels ||
118 out->channel_layout[i] >= (int)out->num_channels) {
119 syslog(LOG_ERR, "Fail to create conversion matrix "
120 "due to invalid channel layout");
121 return NULL;
122 }
123 }
124
125 mtx = cras_channel_conv_matrix_alloc(in->num_channels,
126 out->num_channels);
127
128 /* For the in/out format pair which has the same set of channels
129 * in use, create a permutation matrix for them.
130 */
131 for (i = 0; i < CRAS_CH_MAX; i++) {
132 if (in->channel_layout[i] == -1 &&
133 out->channel_layout[i] == -1)
134 continue;
135 if (in->channel_layout[i] != -1 &&
136 out->channel_layout[i] != -1)
137 mtx[out->channel_layout[i]][in->channel_layout[i]] = 1;
138 else if (in->channel_layout[i] != -1) {
139 /* When the same channel does not appear at output
140 * channel layout. Look up for allowed channel
141 * alternatives.
142 */
143 int alt;
144 for (alt = 0; alt <= CRAS_CH_MAX; alt++) {
145 if (alt == CRAS_CH_MAX)
146 goto fail;
147 if (channel_alt[i][alt] &&
148 in->channel_layout[alt] == -1 &&
149 out->channel_layout[alt] != -1) {
150 mtx[out->channel_layout[alt]]
151 [in->channel_layout[i]] = 1;
152 break;
153 }
154 }
155 }
156 }
157
158 return mtx;
159 fail:
160 cras_channel_conv_matrix_destroy(mtx, out->num_channels);
161 return NULL;
162 }
163