Mercurial > audio-send
diff 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 |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/Alc/panning.c Tue Oct 25 13:02:31 2011 -0700 1.3 @@ -0,0 +1,313 @@ 1.4 +/** 1.5 + * OpenAL cross platform audio library 1.6 + * Copyright (C) 1999-2010 by authors. 1.7 + * This library is free software; you can redistribute it and/or 1.8 + * modify it under the terms of the GNU Library General Public 1.9 + * License as published by the Free Software Foundation; either 1.10 + * version 2 of the License, or (at your option) any later version. 1.11 + * 1.12 + * This library is distributed in the hope that it will be useful, 1.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 1.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1.15 + * Library General Public License for more details. 1.16 + * 1.17 + * You should have received a copy of the GNU Library General Public 1.18 + * License along with this library; if not, write to the 1.19 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 1.20 + * Boston, MA 02111-1307, USA. 1.21 + * Or go to http://www.gnu.org/copyleft/lgpl.html 1.22 + */ 1.23 + 1.24 +#include "config.h" 1.25 + 1.26 +#include <math.h> 1.27 +#include <stdlib.h> 1.28 +#include <string.h> 1.29 +#include <ctype.h> 1.30 +#include <assert.h> 1.31 + 1.32 +#include "alMain.h" 1.33 +#include "AL/al.h" 1.34 +#include "AL/alc.h" 1.35 +#include "alu.h" 1.36 + 1.37 +static void SetSpeakerArrangement(const char *name, ALfloat SpeakerAngle[MAXCHANNELS], 1.38 + enum Channel Speaker2Chan[MAXCHANNELS], ALint chans) 1.39 +{ 1.40 + char layout_str[256]; 1.41 + char *confkey, *next; 1.42 + char *sep, *end; 1.43 + enum Channel val; 1.44 + int i; 1.45 + 1.46 + if(!ConfigValueExists(NULL, name)) 1.47 + name = "layout"; 1.48 + 1.49 + strncpy(layout_str, GetConfigValue(NULL, name, ""), sizeof(layout_str)); 1.50 + layout_str[sizeof(layout_str)-1] = 0; 1.51 + 1.52 + if(!layout_str[0]) 1.53 + return; 1.54 + 1.55 + next = confkey = layout_str; 1.56 + while(next && *next) 1.57 + { 1.58 + confkey = next; 1.59 + next = strchr(confkey, ','); 1.60 + if(next) 1.61 + { 1.62 + *next = 0; 1.63 + do { 1.64 + next++; 1.65 + } while(isspace(*next) || *next == ','); 1.66 + } 1.67 + 1.68 + sep = strchr(confkey, '='); 1.69 + if(!sep || confkey == sep) 1.70 + continue; 1.71 + 1.72 + end = sep - 1; 1.73 + while(isspace(*end) && end != confkey) 1.74 + end--; 1.75 + *(++end) = 0; 1.76 + 1.77 + if(strcmp(confkey, "fl") == 0 || strcmp(confkey, "front-left") == 0) 1.78 + val = FRONT_LEFT; 1.79 + else if(strcmp(confkey, "fr") == 0 || strcmp(confkey, "front-right") == 0) 1.80 + val = FRONT_RIGHT; 1.81 + else if(strcmp(confkey, "fc") == 0 || strcmp(confkey, "front-center") == 0) 1.82 + val = FRONT_CENTER; 1.83 + else if(strcmp(confkey, "bl") == 0 || strcmp(confkey, "back-left") == 0) 1.84 + val = BACK_LEFT; 1.85 + else if(strcmp(confkey, "br") == 0 || strcmp(confkey, "back-right") == 0) 1.86 + val = BACK_RIGHT; 1.87 + else if(strcmp(confkey, "bc") == 0 || strcmp(confkey, "back-center") == 0) 1.88 + val = BACK_CENTER; 1.89 + else if(strcmp(confkey, "sl") == 0 || strcmp(confkey, "side-left") == 0) 1.90 + val = SIDE_LEFT; 1.91 + else if(strcmp(confkey, "sr") == 0 || strcmp(confkey, "side-right") == 0) 1.92 + val = SIDE_RIGHT; 1.93 + else 1.94 + { 1.95 + ERR("Unknown speaker for %s: \"%s\"\n", name, confkey); 1.96 + continue; 1.97 + } 1.98 + 1.99 + *(sep++) = 0; 1.100 + while(isspace(*sep)) 1.101 + sep++; 1.102 + 1.103 + for(i = 0;i < chans;i++) 1.104 + { 1.105 + if(Speaker2Chan[i] == val) 1.106 + { 1.107 + long angle = strtol(sep, NULL, 10); 1.108 + if(angle >= -180 && angle <= 180) 1.109 + SpeakerAngle[i] = angle * M_PI/180.0f; 1.110 + else 1.111 + ERR("Invalid angle for speaker \"%s\": %ld\n", confkey, angle); 1.112 + break; 1.113 + } 1.114 + } 1.115 + } 1.116 + 1.117 + for(i = 0;i < chans;i++) 1.118 + { 1.119 + int min = i; 1.120 + int i2; 1.121 + 1.122 + for(i2 = i+1;i2 < chans;i2++) 1.123 + { 1.124 + if(SpeakerAngle[i2] < SpeakerAngle[min]) 1.125 + min = i2; 1.126 + } 1.127 + 1.128 + if(min != i) 1.129 + { 1.130 + ALfloat tmpf; 1.131 + enum Channel tmpc; 1.132 + 1.133 + tmpf = SpeakerAngle[i]; 1.134 + SpeakerAngle[i] = SpeakerAngle[min]; 1.135 + SpeakerAngle[min] = tmpf; 1.136 + 1.137 + tmpc = Speaker2Chan[i]; 1.138 + Speaker2Chan[i] = Speaker2Chan[min]; 1.139 + Speaker2Chan[min] = tmpc; 1.140 + } 1.141 + } 1.142 +} 1.143 + 1.144 +static ALfloat aluLUTpos2Angle(ALint pos) 1.145 +{ 1.146 + if(pos < QUADRANT_NUM) 1.147 + return aluAtan((ALfloat)pos / (ALfloat)(QUADRANT_NUM - pos)); 1.148 + if(pos < 2 * QUADRANT_NUM) 1.149 + return M_PI_2 + aluAtan((ALfloat)(pos - QUADRANT_NUM) / (ALfloat)(2 * QUADRANT_NUM - pos)); 1.150 + if(pos < 3 * QUADRANT_NUM) 1.151 + return aluAtan((ALfloat)(pos - 2 * QUADRANT_NUM) / (ALfloat)(3 * QUADRANT_NUM - pos)) - M_PI; 1.152 + return aluAtan((ALfloat)(pos - 3 * QUADRANT_NUM) / (ALfloat)(4 * QUADRANT_NUM - pos)) - M_PI_2; 1.153 +} 1.154 + 1.155 +ALint aluCart2LUTpos(ALfloat re, ALfloat im) 1.156 +{ 1.157 + ALint pos = 0; 1.158 + ALfloat denom = aluFabs(re) + aluFabs(im); 1.159 + if(denom > 0.0f) 1.160 + pos = (ALint)(QUADRANT_NUM*aluFabs(im) / denom + 0.5); 1.161 + 1.162 + if(re < 0.0) 1.163 + pos = 2 * QUADRANT_NUM - pos; 1.164 + if(im < 0.0) 1.165 + pos = LUT_NUM - pos; 1.166 + return pos%LUT_NUM; 1.167 +} 1.168 + 1.169 +ALvoid aluInitPanning(ALCdevice *Device) 1.170 +{ 1.171 + ALfloat SpeakerAngle[MAXCHANNELS]; 1.172 + enum Channel *Speaker2Chan; 1.173 + ALfloat Alpha, Theta; 1.174 + ALint pos; 1.175 + ALuint s; 1.176 + 1.177 + Speaker2Chan = Device->Speaker2Chan; 1.178 + switch(Device->FmtChans) 1.179 + { 1.180 + case DevFmtMono: 1.181 + Device->NumChan = 1; 1.182 + Speaker2Chan[0] = FRONT_CENTER; 1.183 + SpeakerAngle[0] = 0.0f * M_PI/180.0f; 1.184 + break; 1.185 + 1.186 + case DevFmtStereo: 1.187 + Device->NumChan = 2; 1.188 + Speaker2Chan[0] = FRONT_LEFT; 1.189 + Speaker2Chan[1] = FRONT_RIGHT; 1.190 + SpeakerAngle[0] = -90.0f * M_PI/180.0f; 1.191 + SpeakerAngle[1] = 90.0f * M_PI/180.0f; 1.192 + SetSpeakerArrangement("layout_STEREO", SpeakerAngle, Speaker2Chan, Device->NumChan); 1.193 + break; 1.194 + 1.195 + case DevFmtQuad: 1.196 + Device->NumChan = 4; 1.197 + Speaker2Chan[0] = BACK_LEFT; 1.198 + Speaker2Chan[1] = FRONT_LEFT; 1.199 + Speaker2Chan[2] = FRONT_RIGHT; 1.200 + Speaker2Chan[3] = BACK_RIGHT; 1.201 + SpeakerAngle[0] = -135.0f * M_PI/180.0f; 1.202 + SpeakerAngle[1] = -45.0f * M_PI/180.0f; 1.203 + SpeakerAngle[2] = 45.0f * M_PI/180.0f; 1.204 + SpeakerAngle[3] = 135.0f * M_PI/180.0f; 1.205 + SetSpeakerArrangement("layout_QUAD", SpeakerAngle, Speaker2Chan, Device->NumChan); 1.206 + break; 1.207 + 1.208 + case DevFmtX51: 1.209 + Device->NumChan = 5; 1.210 + Speaker2Chan[0] = BACK_LEFT; 1.211 + Speaker2Chan[1] = FRONT_LEFT; 1.212 + Speaker2Chan[2] = FRONT_CENTER; 1.213 + Speaker2Chan[3] = FRONT_RIGHT; 1.214 + Speaker2Chan[4] = BACK_RIGHT; 1.215 + SpeakerAngle[0] = -110.0f * M_PI/180.0f; 1.216 + SpeakerAngle[1] = -30.0f * M_PI/180.0f; 1.217 + SpeakerAngle[2] = 0.0f * M_PI/180.0f; 1.218 + SpeakerAngle[3] = 30.0f * M_PI/180.0f; 1.219 + SpeakerAngle[4] = 110.0f * M_PI/180.0f; 1.220 + SetSpeakerArrangement("layout_51CHN", SpeakerAngle, Speaker2Chan, Device->NumChan); 1.221 + break; 1.222 + 1.223 + case DevFmtX51Side: 1.224 + Device->NumChan = 5; 1.225 + Speaker2Chan[0] = SIDE_LEFT; 1.226 + Speaker2Chan[1] = FRONT_LEFT; 1.227 + Speaker2Chan[2] = FRONT_CENTER; 1.228 + Speaker2Chan[3] = FRONT_RIGHT; 1.229 + Speaker2Chan[4] = SIDE_RIGHT; 1.230 + SpeakerAngle[0] = -90.0f * M_PI/180.0f; 1.231 + SpeakerAngle[1] = -30.0f * M_PI/180.0f; 1.232 + SpeakerAngle[2] = 0.0f * M_PI/180.0f; 1.233 + SpeakerAngle[3] = 30.0f * M_PI/180.0f; 1.234 + SpeakerAngle[4] = 90.0f * M_PI/180.0f; 1.235 + SetSpeakerArrangement("layout_51SIDECHN", SpeakerAngle, Speaker2Chan, Device->NumChan); 1.236 + break; 1.237 + 1.238 + case DevFmtX61: 1.239 + Device->NumChan = 6; 1.240 + Speaker2Chan[0] = SIDE_LEFT; 1.241 + Speaker2Chan[1] = FRONT_LEFT; 1.242 + Speaker2Chan[2] = FRONT_CENTER; 1.243 + Speaker2Chan[3] = FRONT_RIGHT; 1.244 + Speaker2Chan[4] = SIDE_RIGHT; 1.245 + Speaker2Chan[5] = BACK_CENTER; 1.246 + SpeakerAngle[0] = -90.0f * M_PI/180.0f; 1.247 + SpeakerAngle[1] = -30.0f * M_PI/180.0f; 1.248 + SpeakerAngle[2] = 0.0f * M_PI/180.0f; 1.249 + SpeakerAngle[3] = 30.0f * M_PI/180.0f; 1.250 + SpeakerAngle[4] = 90.0f * M_PI/180.0f; 1.251 + SpeakerAngle[5] = 180.0f * M_PI/180.0f; 1.252 + SetSpeakerArrangement("layout_61CHN", SpeakerAngle, Speaker2Chan, Device->NumChan); 1.253 + break; 1.254 + 1.255 + case DevFmtX71: 1.256 + Device->NumChan = 7; 1.257 + Speaker2Chan[0] = BACK_LEFT; 1.258 + Speaker2Chan[1] = SIDE_LEFT; 1.259 + Speaker2Chan[2] = FRONT_LEFT; 1.260 + Speaker2Chan[3] = FRONT_CENTER; 1.261 + Speaker2Chan[4] = FRONT_RIGHT; 1.262 + Speaker2Chan[5] = SIDE_RIGHT; 1.263 + Speaker2Chan[6] = BACK_RIGHT; 1.264 + SpeakerAngle[0] = -150.0f * M_PI/180.0f; 1.265 + SpeakerAngle[1] = -90.0f * M_PI/180.0f; 1.266 + SpeakerAngle[2] = -30.0f * M_PI/180.0f; 1.267 + SpeakerAngle[3] = 0.0f * M_PI/180.0f; 1.268 + SpeakerAngle[4] = 30.0f * M_PI/180.0f; 1.269 + SpeakerAngle[5] = 90.0f * M_PI/180.0f; 1.270 + SpeakerAngle[6] = 150.0f * M_PI/180.0f; 1.271 + SetSpeakerArrangement("layout_71CHN", SpeakerAngle, Speaker2Chan, Device->NumChan); 1.272 + break; 1.273 + } 1.274 + 1.275 + for(pos = 0; pos < LUT_NUM; pos++) 1.276 + { 1.277 + ALfloat *PanningLUT = Device->PanningLUT[pos]; 1.278 + 1.279 + /* clear all values */ 1.280 + for(s = 0; s < MAXCHANNELS; s++) 1.281 + PanningLUT[s] = 0.0f; 1.282 + 1.283 + if(Device->NumChan == 1) 1.284 + { 1.285 + PanningLUT[Speaker2Chan[0]] = 1.0f; 1.286 + continue; 1.287 + } 1.288 + 1.289 + /* source angle */ 1.290 + Theta = aluLUTpos2Angle(pos); 1.291 + 1.292 + /* set panning values */ 1.293 + for(s = 0; s < Device->NumChan - 1; s++) 1.294 + { 1.295 + if(Theta >= SpeakerAngle[s] && Theta < SpeakerAngle[s+1]) 1.296 + { 1.297 + /* source between speaker s and speaker s+1 */ 1.298 + Alpha = M_PI_2 * (Theta-SpeakerAngle[s]) / 1.299 + (SpeakerAngle[s+1]-SpeakerAngle[s]); 1.300 + PanningLUT[Speaker2Chan[s]] = cos(Alpha); 1.301 + PanningLUT[Speaker2Chan[s+1]] = sin(Alpha); 1.302 + break; 1.303 + } 1.304 + } 1.305 + if(s == Device->NumChan - 1) 1.306 + { 1.307 + /* source between last and first speaker */ 1.308 + if(Theta < SpeakerAngle[0]) 1.309 + Theta += 2.0f * M_PI; 1.310 + Alpha = M_PI_2 * (Theta-SpeakerAngle[s]) / 1.311 + (2.0f * M_PI + SpeakerAngle[0]-SpeakerAngle[s]); 1.312 + PanningLUT[Speaker2Chan[s]] = cos(Alpha); 1.313 + PanningLUT[Speaker2Chan[0]] = sin(Alpha); 1.314 + } 1.315 + } 1.316 +}