annotate Alc/panning.c @ 0:f9476ff7637e

initial forking of open-al to create multiple listeners
author Robert McIntyre <rlm@mit.edu>
date Tue, 25 Oct 2011 13:02:31 -0700
parents
children
rev   line source
rlm@0 1 /**
rlm@0 2 * OpenAL cross platform audio library
rlm@0 3 * Copyright (C) 1999-2010 by authors.
rlm@0 4 * This library is free software; you can redistribute it and/or
rlm@0 5 * modify it under the terms of the GNU Library General Public
rlm@0 6 * License as published by the Free Software Foundation; either
rlm@0 7 * version 2 of the License, or (at your option) any later version.
rlm@0 8 *
rlm@0 9 * This library is distributed in the hope that it will be useful,
rlm@0 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
rlm@0 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
rlm@0 12 * Library General Public License for more details.
rlm@0 13 *
rlm@0 14 * You should have received a copy of the GNU Library General Public
rlm@0 15 * License along with this library; if not, write to the
rlm@0 16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
rlm@0 17 * Boston, MA 02111-1307, USA.
rlm@0 18 * Or go to http://www.gnu.org/copyleft/lgpl.html
rlm@0 19 */
rlm@0 20
rlm@0 21 #include "config.h"
rlm@0 22
rlm@0 23 #include <math.h>
rlm@0 24 #include <stdlib.h>
rlm@0 25 #include <string.h>
rlm@0 26 #include <ctype.h>
rlm@0 27 #include <assert.h>
rlm@0 28
rlm@0 29 #include "alMain.h"
rlm@0 30 #include "AL/al.h"
rlm@0 31 #include "AL/alc.h"
rlm@0 32 #include "alu.h"
rlm@0 33
rlm@0 34 static void SetSpeakerArrangement(const char *name, ALfloat SpeakerAngle[MAXCHANNELS],
rlm@0 35 enum Channel Speaker2Chan[MAXCHANNELS], ALint chans)
rlm@0 36 {
rlm@0 37 char layout_str[256];
rlm@0 38 char *confkey, *next;
rlm@0 39 char *sep, *end;
rlm@0 40 enum Channel val;
rlm@0 41 int i;
rlm@0 42
rlm@0 43 if(!ConfigValueExists(NULL, name))
rlm@0 44 name = "layout";
rlm@0 45
rlm@0 46 strncpy(layout_str, GetConfigValue(NULL, name, ""), sizeof(layout_str));
rlm@0 47 layout_str[sizeof(layout_str)-1] = 0;
rlm@0 48
rlm@0 49 if(!layout_str[0])
rlm@0 50 return;
rlm@0 51
rlm@0 52 next = confkey = layout_str;
rlm@0 53 while(next && *next)
rlm@0 54 {
rlm@0 55 confkey = next;
rlm@0 56 next = strchr(confkey, ',');
rlm@0 57 if(next)
rlm@0 58 {
rlm@0 59 *next = 0;
rlm@0 60 do {
rlm@0 61 next++;
rlm@0 62 } while(isspace(*next) || *next == ',');
rlm@0 63 }
rlm@0 64
rlm@0 65 sep = strchr(confkey, '=');
rlm@0 66 if(!sep || confkey == sep)
rlm@0 67 continue;
rlm@0 68
rlm@0 69 end = sep - 1;
rlm@0 70 while(isspace(*end) && end != confkey)
rlm@0 71 end--;
rlm@0 72 *(++end) = 0;
rlm@0 73
rlm@0 74 if(strcmp(confkey, "fl") == 0 || strcmp(confkey, "front-left") == 0)
rlm@0 75 val = FRONT_LEFT;
rlm@0 76 else if(strcmp(confkey, "fr") == 0 || strcmp(confkey, "front-right") == 0)
rlm@0 77 val = FRONT_RIGHT;
rlm@0 78 else if(strcmp(confkey, "fc") == 0 || strcmp(confkey, "front-center") == 0)
rlm@0 79 val = FRONT_CENTER;
rlm@0 80 else if(strcmp(confkey, "bl") == 0 || strcmp(confkey, "back-left") == 0)
rlm@0 81 val = BACK_LEFT;
rlm@0 82 else if(strcmp(confkey, "br") == 0 || strcmp(confkey, "back-right") == 0)
rlm@0 83 val = BACK_RIGHT;
rlm@0 84 else if(strcmp(confkey, "bc") == 0 || strcmp(confkey, "back-center") == 0)
rlm@0 85 val = BACK_CENTER;
rlm@0 86 else if(strcmp(confkey, "sl") == 0 || strcmp(confkey, "side-left") == 0)
rlm@0 87 val = SIDE_LEFT;
rlm@0 88 else if(strcmp(confkey, "sr") == 0 || strcmp(confkey, "side-right") == 0)
rlm@0 89 val = SIDE_RIGHT;
rlm@0 90 else
rlm@0 91 {
rlm@0 92 ERR("Unknown speaker for %s: \"%s\"\n", name, confkey);
rlm@0 93 continue;
rlm@0 94 }
rlm@0 95
rlm@0 96 *(sep++) = 0;
rlm@0 97 while(isspace(*sep))
rlm@0 98 sep++;
rlm@0 99
rlm@0 100 for(i = 0;i < chans;i++)
rlm@0 101 {
rlm@0 102 if(Speaker2Chan[i] == val)
rlm@0 103 {
rlm@0 104 long angle = strtol(sep, NULL, 10);
rlm@0 105 if(angle >= -180 && angle <= 180)
rlm@0 106 SpeakerAngle[i] = angle * M_PI/180.0f;
rlm@0 107 else
rlm@0 108 ERR("Invalid angle for speaker \"%s\": %ld\n", confkey, angle);
rlm@0 109 break;
rlm@0 110 }
rlm@0 111 }
rlm@0 112 }
rlm@0 113
rlm@0 114 for(i = 0;i < chans;i++)
rlm@0 115 {
rlm@0 116 int min = i;
rlm@0 117 int i2;
rlm@0 118
rlm@0 119 for(i2 = i+1;i2 < chans;i2++)
rlm@0 120 {
rlm@0 121 if(SpeakerAngle[i2] < SpeakerAngle[min])
rlm@0 122 min = i2;
rlm@0 123 }
rlm@0 124
rlm@0 125 if(min != i)
rlm@0 126 {
rlm@0 127 ALfloat tmpf;
rlm@0 128 enum Channel tmpc;
rlm@0 129
rlm@0 130 tmpf = SpeakerAngle[i];
rlm@0 131 SpeakerAngle[i] = SpeakerAngle[min];
rlm@0 132 SpeakerAngle[min] = tmpf;
rlm@0 133
rlm@0 134 tmpc = Speaker2Chan[i];
rlm@0 135 Speaker2Chan[i] = Speaker2Chan[min];
rlm@0 136 Speaker2Chan[min] = tmpc;
rlm@0 137 }
rlm@0 138 }
rlm@0 139 }
rlm@0 140
rlm@0 141 static ALfloat aluLUTpos2Angle(ALint pos)
rlm@0 142 {
rlm@0 143 if(pos < QUADRANT_NUM)
rlm@0 144 return aluAtan((ALfloat)pos / (ALfloat)(QUADRANT_NUM - pos));
rlm@0 145 if(pos < 2 * QUADRANT_NUM)
rlm@0 146 return M_PI_2 + aluAtan((ALfloat)(pos - QUADRANT_NUM) / (ALfloat)(2 * QUADRANT_NUM - pos));
rlm@0 147 if(pos < 3 * QUADRANT_NUM)
rlm@0 148 return aluAtan((ALfloat)(pos - 2 * QUADRANT_NUM) / (ALfloat)(3 * QUADRANT_NUM - pos)) - M_PI;
rlm@0 149 return aluAtan((ALfloat)(pos - 3 * QUADRANT_NUM) / (ALfloat)(4 * QUADRANT_NUM - pos)) - M_PI_2;
rlm@0 150 }
rlm@0 151
rlm@0 152 ALint aluCart2LUTpos(ALfloat re, ALfloat im)
rlm@0 153 {
rlm@0 154 ALint pos = 0;
rlm@0 155 ALfloat denom = aluFabs(re) + aluFabs(im);
rlm@0 156 if(denom > 0.0f)
rlm@0 157 pos = (ALint)(QUADRANT_NUM*aluFabs(im) / denom + 0.5);
rlm@0 158
rlm@0 159 if(re < 0.0)
rlm@0 160 pos = 2 * QUADRANT_NUM - pos;
rlm@0 161 if(im < 0.0)
rlm@0 162 pos = LUT_NUM - pos;
rlm@0 163 return pos%LUT_NUM;
rlm@0 164 }
rlm@0 165
rlm@0 166 ALvoid aluInitPanning(ALCdevice *Device)
rlm@0 167 {
rlm@0 168 ALfloat SpeakerAngle[MAXCHANNELS];
rlm@0 169 enum Channel *Speaker2Chan;
rlm@0 170 ALfloat Alpha, Theta;
rlm@0 171 ALint pos;
rlm@0 172 ALuint s;
rlm@0 173
rlm@0 174 Speaker2Chan = Device->Speaker2Chan;
rlm@0 175 switch(Device->FmtChans)
rlm@0 176 {
rlm@0 177 case DevFmtMono:
rlm@0 178 Device->NumChan = 1;
rlm@0 179 Speaker2Chan[0] = FRONT_CENTER;
rlm@0 180 SpeakerAngle[0] = 0.0f * M_PI/180.0f;
rlm@0 181 break;
rlm@0 182
rlm@0 183 case DevFmtStereo:
rlm@0 184 Device->NumChan = 2;
rlm@0 185 Speaker2Chan[0] = FRONT_LEFT;
rlm@0 186 Speaker2Chan[1] = FRONT_RIGHT;
rlm@0 187 SpeakerAngle[0] = -90.0f * M_PI/180.0f;
rlm@0 188 SpeakerAngle[1] = 90.0f * M_PI/180.0f;
rlm@0 189 SetSpeakerArrangement("layout_STEREO", SpeakerAngle, Speaker2Chan, Device->NumChan);
rlm@0 190 break;
rlm@0 191
rlm@0 192 case DevFmtQuad:
rlm@0 193 Device->NumChan = 4;
rlm@0 194 Speaker2Chan[0] = BACK_LEFT;
rlm@0 195 Speaker2Chan[1] = FRONT_LEFT;
rlm@0 196 Speaker2Chan[2] = FRONT_RIGHT;
rlm@0 197 Speaker2Chan[3] = BACK_RIGHT;
rlm@0 198 SpeakerAngle[0] = -135.0f * M_PI/180.0f;
rlm@0 199 SpeakerAngle[1] = -45.0f * M_PI/180.0f;
rlm@0 200 SpeakerAngle[2] = 45.0f * M_PI/180.0f;
rlm@0 201 SpeakerAngle[3] = 135.0f * M_PI/180.0f;
rlm@0 202 SetSpeakerArrangement("layout_QUAD", SpeakerAngle, Speaker2Chan, Device->NumChan);
rlm@0 203 break;
rlm@0 204
rlm@0 205 case DevFmtX51:
rlm@0 206 Device->NumChan = 5;
rlm@0 207 Speaker2Chan[0] = BACK_LEFT;
rlm@0 208 Speaker2Chan[1] = FRONT_LEFT;
rlm@0 209 Speaker2Chan[2] = FRONT_CENTER;
rlm@0 210 Speaker2Chan[3] = FRONT_RIGHT;
rlm@0 211 Speaker2Chan[4] = BACK_RIGHT;
rlm@0 212 SpeakerAngle[0] = -110.0f * M_PI/180.0f;
rlm@0 213 SpeakerAngle[1] = -30.0f * M_PI/180.0f;
rlm@0 214 SpeakerAngle[2] = 0.0f * M_PI/180.0f;
rlm@0 215 SpeakerAngle[3] = 30.0f * M_PI/180.0f;
rlm@0 216 SpeakerAngle[4] = 110.0f * M_PI/180.0f;
rlm@0 217 SetSpeakerArrangement("layout_51CHN", SpeakerAngle, Speaker2Chan, Device->NumChan);
rlm@0 218 break;
rlm@0 219
rlm@0 220 case DevFmtX51Side:
rlm@0 221 Device->NumChan = 5;
rlm@0 222 Speaker2Chan[0] = SIDE_LEFT;
rlm@0 223 Speaker2Chan[1] = FRONT_LEFT;
rlm@0 224 Speaker2Chan[2] = FRONT_CENTER;
rlm@0 225 Speaker2Chan[3] = FRONT_RIGHT;
rlm@0 226 Speaker2Chan[4] = SIDE_RIGHT;
rlm@0 227 SpeakerAngle[0] = -90.0f * M_PI/180.0f;
rlm@0 228 SpeakerAngle[1] = -30.0f * M_PI/180.0f;
rlm@0 229 SpeakerAngle[2] = 0.0f * M_PI/180.0f;
rlm@0 230 SpeakerAngle[3] = 30.0f * M_PI/180.0f;
rlm@0 231 SpeakerAngle[4] = 90.0f * M_PI/180.0f;
rlm@0 232 SetSpeakerArrangement("layout_51SIDECHN", SpeakerAngle, Speaker2Chan, Device->NumChan);
rlm@0 233 break;
rlm@0 234
rlm@0 235 case DevFmtX61:
rlm@0 236 Device->NumChan = 6;
rlm@0 237 Speaker2Chan[0] = SIDE_LEFT;
rlm@0 238 Speaker2Chan[1] = FRONT_LEFT;
rlm@0 239 Speaker2Chan[2] = FRONT_CENTER;
rlm@0 240 Speaker2Chan[3] = FRONT_RIGHT;
rlm@0 241 Speaker2Chan[4] = SIDE_RIGHT;
rlm@0 242 Speaker2Chan[5] = BACK_CENTER;
rlm@0 243 SpeakerAngle[0] = -90.0f * M_PI/180.0f;
rlm@0 244 SpeakerAngle[1] = -30.0f * M_PI/180.0f;
rlm@0 245 SpeakerAngle[2] = 0.0f * M_PI/180.0f;
rlm@0 246 SpeakerAngle[3] = 30.0f * M_PI/180.0f;
rlm@0 247 SpeakerAngle[4] = 90.0f * M_PI/180.0f;
rlm@0 248 SpeakerAngle[5] = 180.0f * M_PI/180.0f;
rlm@0 249 SetSpeakerArrangement("layout_61CHN", SpeakerAngle, Speaker2Chan, Device->NumChan);
rlm@0 250 break;
rlm@0 251
rlm@0 252 case DevFmtX71:
rlm@0 253 Device->NumChan = 7;
rlm@0 254 Speaker2Chan[0] = BACK_LEFT;
rlm@0 255 Speaker2Chan[1] = SIDE_LEFT;
rlm@0 256 Speaker2Chan[2] = FRONT_LEFT;
rlm@0 257 Speaker2Chan[3] = FRONT_CENTER;
rlm@0 258 Speaker2Chan[4] = FRONT_RIGHT;
rlm@0 259 Speaker2Chan[5] = SIDE_RIGHT;
rlm@0 260 Speaker2Chan[6] = BACK_RIGHT;
rlm@0 261 SpeakerAngle[0] = -150.0f * M_PI/180.0f;
rlm@0 262 SpeakerAngle[1] = -90.0f * M_PI/180.0f;
rlm@0 263 SpeakerAngle[2] = -30.0f * M_PI/180.0f;
rlm@0 264 SpeakerAngle[3] = 0.0f * M_PI/180.0f;
rlm@0 265 SpeakerAngle[4] = 30.0f * M_PI/180.0f;
rlm@0 266 SpeakerAngle[5] = 90.0f * M_PI/180.0f;
rlm@0 267 SpeakerAngle[6] = 150.0f * M_PI/180.0f;
rlm@0 268 SetSpeakerArrangement("layout_71CHN", SpeakerAngle, Speaker2Chan, Device->NumChan);
rlm@0 269 break;
rlm@0 270 }
rlm@0 271
rlm@0 272 for(pos = 0; pos < LUT_NUM; pos++)
rlm@0 273 {
rlm@0 274 ALfloat *PanningLUT = Device->PanningLUT[pos];
rlm@0 275
rlm@0 276 /* clear all values */
rlm@0 277 for(s = 0; s < MAXCHANNELS; s++)
rlm@0 278 PanningLUT[s] = 0.0f;
rlm@0 279
rlm@0 280 if(Device->NumChan == 1)
rlm@0 281 {
rlm@0 282 PanningLUT[Speaker2Chan[0]] = 1.0f;
rlm@0 283 continue;
rlm@0 284 }
rlm@0 285
rlm@0 286 /* source angle */
rlm@0 287 Theta = aluLUTpos2Angle(pos);
rlm@0 288
rlm@0 289 /* set panning values */
rlm@0 290 for(s = 0; s < Device->NumChan - 1; s++)
rlm@0 291 {
rlm@0 292 if(Theta >= SpeakerAngle[s] && Theta < SpeakerAngle[s+1])
rlm@0 293 {
rlm@0 294 /* source between speaker s and speaker s+1 */
rlm@0 295 Alpha = M_PI_2 * (Theta-SpeakerAngle[s]) /
rlm@0 296 (SpeakerAngle[s+1]-SpeakerAngle[s]);
rlm@0 297 PanningLUT[Speaker2Chan[s]] = cos(Alpha);
rlm@0 298 PanningLUT[Speaker2Chan[s+1]] = sin(Alpha);
rlm@0 299 break;
rlm@0 300 }
rlm@0 301 }
rlm@0 302 if(s == Device->NumChan - 1)
rlm@0 303 {
rlm@0 304 /* source between last and first speaker */
rlm@0 305 if(Theta < SpeakerAngle[0])
rlm@0 306 Theta += 2.0f * M_PI;
rlm@0 307 Alpha = M_PI_2 * (Theta-SpeakerAngle[s]) /
rlm@0 308 (2.0f * M_PI + SpeakerAngle[0]-SpeakerAngle[s]);
rlm@0 309 PanningLUT[Speaker2Chan[s]] = cos(Alpha);
rlm@0 310 PanningLUT[Speaker2Chan[0]] = sin(Alpha);
rlm@0 311 }
rlm@0 312 }
rlm@0 313 }