1/* 2** Copyright (C) 2009-2014 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 36static 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 42static const int one_chan_mono [1] = { SF_CHANNEL_MAP_MONO } ; 43 44static const AIFF_CAF_CHANNEL_MAP one_chan [] = 45{ { (100 << 16) | 1, one_chan_mono, "mono" } 46} ; /* one_chan */ 47 48 49static const int two_channel_stereo [2] = { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT } ; 50 51static 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 64static const int three_channel_mpeg_30a [3] = 65 { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER } ; 66static const int three_channel_mpeg_30b [3] = 67 { SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT } ; 68static const int three_channel_itu_21 [3] = 69 { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_CENTER } ; 70static const int three_channel_dvd_4 [3] = 71 { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_LFE } ; 72 73static 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 81static 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 } ; 83static 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 } ; 85static 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 } ; 87static 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 } ; 89static 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 } ; 91static 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 } ; 93static 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 96static 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 107static 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 } ; 109static 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 } ; 111static 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 } ; 113static 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 } ; 115static 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 } ; 117static 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 } ; 119static 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 } ; 121static 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 124static 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 136static 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 } ; 138static 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 } ; 140static 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 } ; 142static 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 } ; 144static 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 } ; 146static 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 149static 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 160static 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 } ; 162static 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 165static 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 173static 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 199TMH_10_2_std = (145 << 16) | 16, 200// L R C Vhc Lsd Rsd Ls Rs Vhl Vhr Lw Rw Csd Cs LFE1 LFE2 201 202TMH_10_2_full = (146 << 16) | 21, 203// TMH_10_2_std plus: Lc Rc HI VI Haptic 204 205#endif 206 207 208typedef struct 209{ const AIFF_CAF_CHANNEL_MAP * map ; 210 int len ; 211} MAP_MAP ; 212 213static 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 226int 227aiff_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 245const AIFF_CAF_CHANNEL_MAP * 246aiff_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 */ 263