Alexandre Lision | 7c6f4a6 | 2013-09-05 13:27:01 -0400 | [diff] [blame] | 1 | /* |
| 2 | ** Copyright (C) 2009-2011 Erik de Castro Lopo <erikd@mega-nerd.com> |
| 3 | ** |
| 4 | ** This program is free software; you can redistribute it and/or modify |
| 5 | ** it under the terms of the GNU Lesser General Public License as published by |
| 6 | ** the Free Software Foundation; either version 2.1 of the License, or |
| 7 | ** (at your option) any later version. |
| 8 | ** |
| 9 | ** This program is distributed in the hope that it will be useful, |
| 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | ** GNU Lesser General Public License for more details. |
| 13 | ** |
| 14 | ** You should have received a copy of the GNU Lesser General Public License |
| 15 | ** along with this program; if not, write to the Free Software |
| 16 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| 17 | */ |
| 18 | |
| 19 | /* |
| 20 | ** Mostly from "Apple Core Audio Format Specification 1.0": |
| 21 | ** |
| 22 | ** http://developer.apple.com/documentation/MusicAudio/Reference/CAFSpec/CAFSpec.pdf |
| 23 | */ |
| 24 | |
| 25 | #include "sfconfig.h" |
| 26 | |
| 27 | #include <stdio.h> |
| 28 | #include <stdlib.h> |
| 29 | #include <string.h> |
| 30 | |
| 31 | #include "sndfile.h" |
| 32 | #include "common.h" |
| 33 | #include "chanmap.h" |
| 34 | |
| 35 | |
| 36 | static const AIFF_CAF_CHANNEL_MAP zero_chan [] = |
| 37 | { { (0 << 16) | 0, NULL, "Use channel descriptions." }, |
| 38 | { (1 << 16) | 0, NULL, "Use channel bitmap." } |
| 39 | } ; /* zero_chan */ |
| 40 | |
| 41 | |
| 42 | static const int one_chan_mono [1] = { SF_CHANNEL_MAP_MONO } ; |
| 43 | |
| 44 | static const AIFF_CAF_CHANNEL_MAP one_chan [] = |
| 45 | { { (100 << 16) | 1, one_chan_mono, "mono" } |
| 46 | } ; /* one_chan */ |
| 47 | |
| 48 | |
| 49 | static const int two_channel_stereo [2] = { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT } ; |
| 50 | |
| 51 | static const AIFF_CAF_CHANNEL_MAP two_chan [] = |
| 52 | { { (101 << 16) | 2, two_channel_stereo, "stereo (L, R)" }, |
| 53 | { (102 << 16) | 2, two_channel_stereo, "stereo headphones (L, R)" }, |
| 54 | #if 0 |
| 55 | { (103 << 16) | 2, NULL, "matrix stereo (Lt, Rt)" }, |
| 56 | { (104 << 16) | 2, NULL, "2 channels (mid, side)" }, |
| 57 | { (105 << 16) | 2, NULL, "coincident mic pair" }, |
| 58 | { (106 << 16) | 2, NULL, "binaural stereo (L, R)" |
| 59 | } |
| 60 | #endif |
| 61 | } ; /* two_chan */ |
| 62 | |
| 63 | |
| 64 | static const int three_channel_mpeg_30a [3] = |
| 65 | { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER } ; |
| 66 | static const int three_channel_mpeg_30b [3] = |
| 67 | { SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT } ; |
| 68 | static const int three_channel_itu_21 [3] = |
| 69 | { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_CENTER } ; |
| 70 | static const int three_channel_dvd_4 [3] = |
| 71 | { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_LFE } ; |
| 72 | |
| 73 | static const AIFF_CAF_CHANNEL_MAP three_chan [] = |
| 74 | { { (113 << 16) | 3, three_channel_mpeg_30a, "MPEG 3 0 A (L, R, C)" }, |
| 75 | { (114 << 16) | 3, three_channel_mpeg_30b, "MPEG 3 0 B (C, L, R)" }, |
| 76 | { (131 << 16) | 3, three_channel_itu_21, "ITU 2.1 (L, R, Cs)" }, |
| 77 | { (133 << 16) | 3, three_channel_dvd_4, "DVD 4 (L, R, LFE)" } |
| 78 | } ; /* three_chan */ |
| 79 | |
| 80 | |
| 81 | static const int four_channel_ambisonc_b [4] = |
| 82 | { SF_CHANNEL_MAP_AMBISONIC_B_W, SF_CHANNEL_MAP_AMBISONIC_B_X, SF_CHANNEL_MAP_AMBISONIC_B_Y, SF_CHANNEL_MAP_AMBISONIC_B_Z } ; |
| 83 | static const int four_channel_quad [4] = |
| 84 | { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT } ; |
| 85 | static const int four_channel_mpeg_40a [4] = |
| 86 | { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_REAR_CENTER } ; |
| 87 | static const int four_channel_mpeg_40b [4] = |
| 88 | { SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_CENTER } ; |
| 89 | static const int four_channel_itu_23 [4] = |
| 90 | { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT } ; |
| 91 | static const int four_channel_dvd_5 [4] = |
| 92 | { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_LFE, SF_CHANNEL_MAP_REAR_CENTER } ; |
| 93 | static const int four_channel_dvd_10 [4] = |
| 94 | { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE } ; |
| 95 | |
| 96 | static const AIFF_CAF_CHANNEL_MAP four_chan [] = |
| 97 | { { (107 << 16) | 4, four_channel_ambisonc_b, "ambisonic B (W, X, Y, Z)" }, |
| 98 | { (108 << 16) | 4, four_channel_quad, "quad (Lfront, Rfront, Lrear, Rrear)" }, |
| 99 | { (115 << 16) | 4, four_channel_mpeg_40a, "MPEG 4.0 A (L, R, C, Cs)" }, |
| 100 | { (116 << 16) | 4, four_channel_mpeg_40b, "MPEG 4.0 B (C, L, R, Cs)" }, |
| 101 | { (132 << 16) | 4, four_channel_itu_23, "ITU 2.3 (L, R, Ls, Rs)" }, |
| 102 | { (134 << 16) | 4, four_channel_dvd_5, "DVD 5 (L, R, LFE, Cs)" }, |
| 103 | { (136 << 16) | 4, four_channel_dvd_10, "DVD 10 (L, R, C, LFE)" } |
| 104 | } ; /* four_chan */ |
| 105 | |
| 106 | |
| 107 | static const int five_channel_pentagonal [5] = |
| 108 | { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_CENTER } ; |
| 109 | static const int five_channel_mpeg_50_a [5] = |
| 110 | { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT } ; |
| 111 | static const int five_channel_mpeg_50_b [5] = |
| 112 | { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_CENTER } ; |
| 113 | static const int five_channel_mpeg_50_c [5] = |
| 114 | { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT } ; |
| 115 | static const int five_channel_mpeg_50_d [5] = |
| 116 | { SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT } ; |
| 117 | static const int five_channel_dvd_6 [5] = |
| 118 | { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_LFE, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT } ; |
| 119 | static const int five_channel_dvd_11 [5] = |
| 120 | { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE, SF_CHANNEL_MAP_REAR_CENTER } ; |
| 121 | static const int five_channel_dvd_18 [5] = |
| 122 | { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_LFE } ; |
| 123 | |
| 124 | static const AIFF_CAF_CHANNEL_MAP five_chan [] = |
| 125 | { { (109 << 16) | 5, five_channel_pentagonal, "pentagonal (L, R, Lrear, Rrear, C)" }, |
| 126 | { (117 << 16) | 5, five_channel_mpeg_50_a, "MPEG 5.0 A (L, R, C, Ls, Rs)" }, |
| 127 | { (118 << 16) | 5, five_channel_mpeg_50_b, "MPEG 5.0 B (L, R, Ls, Rs, C)" }, |
| 128 | { (119 << 16) | 5, five_channel_mpeg_50_c, "MPEG 5.0 C (L, C, R, Ls, Rs,)" }, |
| 129 | { (120 << 16) | 5, five_channel_mpeg_50_d, "MPEG 5.0 D (C, L, R, Ls, Rs)" }, |
| 130 | { (135 << 16) | 5, five_channel_dvd_6, "DVD 6 (L, R, LFE, Ls, Rs)" }, |
| 131 | { (137 << 16) | 5, five_channel_dvd_11, "DVD 11 (L, R, C, LFE, Cs)" }, |
| 132 | { (138 << 16) | 5, five_channel_dvd_18, "DVD 18 (L, R, Ls, Rs, LFE)" } |
| 133 | } ; /* five_chan */ |
| 134 | |
| 135 | |
| 136 | static const int six_channel_mpeg_51_a [6] = |
| 137 | { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT } ; |
| 138 | static const int six_channel_mpeg_51_b [6] = |
| 139 | { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE } ; |
| 140 | static const int six_channel_mpeg_51_c [6] = |
| 141 | { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_LFE } ; |
| 142 | static const int six_channel_mpeg_51_d [6] = |
| 143 | { SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_LFE } ; |
| 144 | static const int six_channel_audio_unit_60 [6] = |
| 145 | { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_REAR_CENTER } ; |
| 146 | static const int six_channel_aac_60 [6] = |
| 147 | { SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_REAR_CENTER } ; |
| 148 | |
| 149 | static const AIFF_CAF_CHANNEL_MAP six_chan [] = |
| 150 | { { (110 << 16) | 6, NULL, "hexagonal (L, R, Lr, Rr, C, Rear)" }, |
| 151 | { (121 << 16) | 6, six_channel_mpeg_51_a, "MPEG 5.1 A (L, R, C, LFE, Ls, Rs)" }, |
| 152 | { (122 << 16) | 6, six_channel_mpeg_51_b, "MPEG 5.1 B (L, R, Ls, Rs, C, LFE)" }, |
| 153 | { (123 << 16) | 6, six_channel_mpeg_51_c, "MPEG 5.1 C (L, C, R, Ls, Rs, LFE)" }, |
| 154 | { (124 << 16) | 6, six_channel_mpeg_51_d, "MPEG 5.1 D (C, L, R, Ls, Rs, LFE)" }, |
| 155 | { (139 << 16) | 6, six_channel_audio_unit_60, "AudioUnit 6.0 (L, R, Ls, Rs, C, Cs)" }, |
| 156 | { (141 << 16) | 6, six_channel_aac_60, "AAC 6.0 (C, L, R, Ls, Rs, Cs)" } |
| 157 | } ; /* six_chan */ |
| 158 | |
| 159 | |
| 160 | static const int six_channel_mpeg_61a [7] = |
| 161 | { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_REAR_CENTER } ; |
| 162 | static const int six_channel_aac_61 [7] = |
| 163 | { SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_REAR_CENTER, SF_CHANNEL_MAP_LFE } ; |
| 164 | |
| 165 | static const AIFF_CAF_CHANNEL_MAP seven_chan [] = |
| 166 | { { (125 << 16) | 7, six_channel_mpeg_61a, "MPEG 6.1 A (L, R, C, LFE, Ls, Rs, Cs)" }, |
| 167 | { (140 << 16) | 7, NULL, "AudioUnit 7.0 (L, R, Ls, Rs, C, Rls, Rrs)" }, |
| 168 | { (142 << 16) | 7, six_channel_aac_61, "AAC 6.1 (C, L, R, Ls, Rs, Cs, Lfe)" }, |
| 169 | { (143 << 16) | 7, NULL, "AAC 7.0 (C, L, R, Ls, Rs, Rls, Rrs,)" } |
| 170 | } ; /* seven_chan */ |
| 171 | |
| 172 | |
| 173 | static const AIFF_CAF_CHANNEL_MAP eight_chan [] = |
| 174 | { { (111 << 16) | 8, NULL, |
| 175 | // front left, front right, rear left, rear right, |
| 176 | // front center, rear center, side left, side right |
| 177 | "octagonal (Lf, Rf, Lr, Rr, Cf, Cr, Ls, Rs)" |
| 178 | }, |
| 179 | { (112 << 16) | 8, NULL, |
| 180 | // left, right, rear left, rear right |
| 181 | // top left, top right, top rear left, top rear right |
| 182 | "cube (L, R, Lrear, Rrear, Ltop, Rtop, Ltoprear, Rtoprear)" |
| 183 | }, |
| 184 | { (126 << 16) | 8, NULL, "MPEG 7.1 A (L, R, C, LFE, Ls, Rs, Lc, Rc)" }, |
| 185 | { (127 << 16) | 8, NULL, "MPEG 7.1 B (C, Lc, Rc, L, R, Ls, Rs, LFE)" }, |
| 186 | { (128 << 16) | 8, NULL, "MPEG 7.1 C (L, R, C, LFE, Ls, R, Rls, Rrs)" }, |
| 187 | { (129 << 16) | 8, NULL, "Emagic Default 7.1 (L, R, Ls, Rs, C, LFE, Lc, Rc)" }, |
| 188 | { (130 << 16) | 8, NULL, |
| 189 | // (ITU_5_1 plus a matrix encoded stereo mix) |
| 190 | "SMPTE DTV (L, R, C, LFE, Ls, Rs, Lt, Rt)" |
| 191 | }, |
| 192 | { (144 << 16) | 8, NULL, "AAC octagonal (C, L, R, Ls, Rs, Rls, Rrs, Cs)" } |
| 193 | } ; /* eight_chan */ |
| 194 | |
| 195 | |
| 196 | |
| 197 | #if 0 |
| 198 | |
| 199 | TMH_10_2_std = (145 << 16) | 16, |
| 200 | // L R C Vhc Lsd Rsd Ls Rs Vhl Vhr Lw Rw Csd Cs LFE1 LFE2 |
| 201 | |
| 202 | TMH_10_2_full = (146 << 16) | 21, |
| 203 | // TMH_10_2_std plus: Lc Rc HI VI Haptic |
| 204 | |
| 205 | #endif |
| 206 | |
| 207 | |
| 208 | typedef struct |
| 209 | { const AIFF_CAF_CHANNEL_MAP * map ; |
| 210 | int len ; |
| 211 | } MAP_MAP ; |
| 212 | |
| 213 | static const MAP_MAP map [] = |
| 214 | { { zero_chan, ARRAY_LEN (zero_chan) }, |
| 215 | { one_chan, ARRAY_LEN (one_chan) }, |
| 216 | { two_chan, ARRAY_LEN (two_chan) }, |
| 217 | { three_chan, ARRAY_LEN (three_chan) }, |
| 218 | { four_chan, ARRAY_LEN (four_chan) }, |
| 219 | { five_chan, ARRAY_LEN (five_chan) }, |
| 220 | { six_chan, ARRAY_LEN (six_chan) }, |
| 221 | { seven_chan, ARRAY_LEN (seven_chan) }, |
| 222 | { eight_chan, ARRAY_LEN (eight_chan) } |
| 223 | } ; /* map */ |
| 224 | |
| 225 | |
| 226 | int |
| 227 | aiff_caf_find_channel_layout_tag (const int *chan_map, int channels) |
| 228 | { const AIFF_CAF_CHANNEL_MAP * curr_map ; |
| 229 | unsigned k, len ; |
| 230 | |
| 231 | if (channels < 1 || channels > ARRAY_LEN (map)) |
| 232 | return 0 ; |
| 233 | |
| 234 | curr_map = map [channels].map ; |
| 235 | len = map [channels].len ; |
| 236 | |
| 237 | for (k = 0 ; k < len ; k++) |
| 238 | if (curr_map [k].channel_map != NULL) |
| 239 | if (memcmp (chan_map, curr_map [k].channel_map, channels * sizeof (chan_map [0])) == 0) |
| 240 | return curr_map [k].channel_layout_tag ; |
| 241 | |
| 242 | return 0 ; |
| 243 | } /* aiff_caf_find_channel_layout_tag */ |
| 244 | |
| 245 | const AIFF_CAF_CHANNEL_MAP * |
| 246 | aiff_caf_of_channel_layout_tag (int tag) |
| 247 | { const AIFF_CAF_CHANNEL_MAP * curr_map ; |
| 248 | unsigned k, len ; |
| 249 | int channels = tag & 0xffff ; |
| 250 | |
| 251 | if (channels < 0 || channels > ARRAY_LEN (map)) |
| 252 | return NULL ; |
| 253 | |
| 254 | curr_map = map [channels].map ; |
| 255 | len = map [channels].len ; |
| 256 | |
| 257 | for (k = 0 ; k < len ; k++) |
| 258 | if (curr_map [k].channel_layout_tag == tag) |
| 259 | return curr_map + k ; |
| 260 | |
| 261 | return NULL ; |
| 262 | } /* aiff_caf_of_channel_layout_tag */ |