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