├── .DS_Store ├── Makefile ├── README.md ├── generateImpulse ├── generateImpulse.c ├── generateImpulse.dSYM └── Contents │ ├── Info (2).plist │ ├── Info.plist │ └── Resources │ └── DWARF │ ├── generateImpulse │ └── generateImpulse (2) ├── impulse.wav └── ss2.png /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Add9Sus4/Ray-Tracing-Impulse-Response-Generator/01e3dd3cf079dd8cae2005f525bf070bcf6e9de9/.DS_Store -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile 3 | # 4 | 5 | # OS X: 6 | CC=gcc -g -D__MACOSX_CORE__ -Wno-deprecated 7 | LIBS=-framework OpenGL -framework GLUT -framework CoreFoundation -lsndfile -lncurses 8 | EXE = generateImpulse 9 | FLAGS=-c -Wall 10 | SRCS = generateImpulse.c 11 | 12 | # Linux: 13 | #CC=gcc -g -Wno-deprecated 14 | #LIBS=-lGL -lGLU -lglut -lportaudio -lsndfile 15 | 16 | all: $(EXE) 17 | 18 | $(EXE): $(SRCS) $(HDRS) 19 | $(CC) $(CFLAGS) -o $@ $(SRCS) $(LIBS) 20 | 21 | clean: 22 | rm -f *~ core $(EXE) *.o output.wav 23 | rm -rf $(EXE).dSYM 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ray-Tracing-Impulse-Response-Generator 2 | Synthesizes a room impulse response using a ray tracing simulation engine. 3 | 4 | ![Screenshot](ss2.png) 5 | 6 | A room impulse response (RIR) is a measure of the acoustic response of a physical space to an impulse (a short burst of sound). 7 | 8 | Typically RIRs are obtained by recording a pistol shot or balloon pop with a microphone placed inside of the room. An RIR can also be obtained by playing a sine sweep through a loudspeaker, recording the result with a microphone, and then deconvolving the resulting sound with the original sine sweep to obtain the impulse response. 9 | 10 | This program aims to simulate the process of recording RIRs using a simple physical model. In this model, the room, sound source, and microphone location are modeled as virtual objects, and rays are sent out from the sound source and propagate throughout the virtual space until they reach the virtual microphone. The sum of the amplitudes of all such rays, combined with the time it takes for them to reach the microphone, creates the impulse response, which is output as a .WAV file. 11 | 12 | This is a simple program that ignores phenomena such as diffraction and interference that can have a significant effect in a real acoustic space. It also does not perform filtering, though this could be achieved simply by passing the impulse response through one or several time-varying digital filters to simulate the effect of frequency-dependent absorption. 13 | 14 | The program has two modes: one mode computes the impulse response quickly but does not provide a visual aid; the other allows the user to view the rays as they propagate throughout the virtual space, which can be interesting but takes a lot longer (as some of the rays might reflect many times before they hit the microphone). 15 | 16 | **Additional notes:** 17 | 18 | The ray tracing algorithm used in this model is stochastic, meaning that rays are randomly given initial direction vectors, and this means that it is not guaranteed, even with identical starting parameters, to produce the same exact impulse response each time it is run. 19 | 20 | The room model is always a rectangular prism. In a future version of this program, more complicated room geometries will be included. 21 | -------------------------------------------------------------------------------- /generateImpulse: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Add9Sus4/Ray-Tracing-Impulse-Response-Generator/01e3dd3cf079dd8cae2005f525bf070bcf6e9de9/generateImpulse -------------------------------------------------------------------------------- /generateImpulse.c: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************* 2 | / Aaron Dawson - C Programming Final Project 3 | / Impulse Response Generator "Impulsinator" 4 | / This program creates an impulse response representative of a given room with various parameters 5 | / and also displays a visual representation of the ray tracing process 6 | / 7 | / 8 | / 9 | *********************************************************************************************************/ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | // OpenGL 23 | #ifdef __MACOSX_CORE__ 24 | #include 25 | #else 26 | #include 27 | #include 28 | #include 29 | #endif 30 | 31 | // General parameters 32 | #define SAMPLE_RATE 44100 // in Hz 33 | #define STEREO 2 34 | #define MONO 1 35 | #define NUM_OUT_CHANNELS STEREO 36 | #define SPEED_OF_SOUND 343 // in meters per second 37 | #define INCHES_PER_METER 39.37 38 | #define OUTFILE_LENGTH_IN_SECONDS 10 // duration of output WAV file 39 | #define NUM_RAYS 10000 // number of rays to be used in the computation 40 | #define LENGTH SAMPLE_RATE * OUTFILE_LENGTH_IN_SECONDS // the length represented in samples 41 | #define GENERATE_IMPULSE false // if true, compute the impulse response and write to WAV file 42 | #define SHOW_VISUAL true // if true, show visual simulation of ray tracing 43 | 44 | // Source location parameters 45 | #define SOURCE_LOCATION_X 0.0 // in meters 46 | #define SOURCE_LOCATION_Y 0.0 // in meters 47 | #define SOURCE_LOCATION_Z 0.0 // in meters 48 | 49 | // Room parameters (X = width, Y = height, Z = depth) 50 | #define ROOM_CENTER_X 0.0 // in meters 51 | #define ROOM_CENTER_Y 0.0 // in meters 52 | #define ROOM_CENTER_Z 0.0 // in meters 53 | #define ROOM_WIDTH_X 5 // in meters 54 | #define ROOM_WIDTH_Y 6 // in meters 55 | #define ROOM_WIDTH_Z 4 // in meters 56 | #define ROOM_ABSORPTION_COEFF 0.99 // scales the amplitude by this amount when a ray collides with a wall 57 | #define LOWPASS_COEFF 0.90 /* filters the sound using a simple lowpass filter with the difference equation: 58 | y[n] = x[n] + ax[n-1] where n is the sample number, y is the output signal, 59 | x is the input signal, and a is equal to LOWPASS_COEFF */ 60 | #define FILTERING true // filtering is only included when this is set to true 61 | 62 | // Microphone parameters 63 | #define MIC_LOCATION_X 0.0 // in meters 64 | #define MIC_LOCATION_Y 1.0 // in meters 65 | #define MIC_LOCATION_Z 0.2 // in meters 66 | #define MIC2_LOCATION_X 0 // in meters 67 | #define MIC2_LOCATION_Y 1.0 // in meters 68 | #define MIC2_LOCATION_Z -0.2 // in meters 69 | #define MIC_WIDTH 1.5/INCHES_PER_METER // in inches; the program assumes both mics are the same size 70 | 71 | // OpenGL parameters 72 | #define PRINT_RAY_INFO false // determines whether or not to print when each ray is received 73 | #define SCALE 400 // scaling factor used to determine initial size of objects drawn on screen 74 | #define INIT_WIDTH 1000 // initial width of the window 75 | #define INIT_HEIGHT 900 // initial height of the window 76 | #define INIT_ANGLE_X 0 // initial angle of rotation about the x axis 77 | #define INIT_ANGLE_Y -15 // initial angle of rotation about the y axis 78 | #define POINT_SIZE 1.0 // how large the points are drawn 79 | #define COLOR_INCR 0.05 // used to change the color of the room when the 'c' key is pressed 80 | #define ROTATION_INCR 0.10f // increment by which the view is rotated 81 | #define ZOOM_AMT 1.001f // value used in calculations for zooming in and out 82 | #define NUM_SIM_RAYS 100000 /* the number of rays that will be drawn on the screen (independent of the actual 83 | rays used in the impulse response simulation) */ 84 | #define SHOW_ABSORPTION true /* if true is selected, lines will get less bright each time they bounce off 85 | of a wall, representing their loss of energy during the collision. */ 86 | #define RAY_SPEED 1 // the speed at which rays move across the screen 87 | #define FADE_AMT 10 /* from 1 to 10; as FADE_AMT increases the ray's tail will fade out quicker. Only 88 | implemented when DRAW_MODE LINES is in effect. */ 89 | #define RAY_SPEED_INCR 2 // increment used to change the speed of the rays on the screen 90 | #define RAY_TAIL_LENGTH 1000 // Do not change this from 1000! 91 | #define POINTS 0 // view rays as points 92 | #define LINES 1 // view rays as lines 93 | #define DRAW_MODE POINTS /* DRAW_MODE refers to how the ray will be drawn. If POINTS is selected, it 94 | will be drawn as a point that moves across the screen. If LINES is selected, it 95 | will be drawn as a line with tail length = RAY_TAIL_LENGTH (kind of like 96 | snake).*/ 97 | 98 | // Print options 99 | #define PRINT_RAY false // determines whether information about each ray is printed when it is received 100 | #define PRINT_INFO true // determines whether timing information and number of rays received is printed 101 | 102 | // Global variables 103 | float g_room_width_x = ROOM_WIDTH_X; 104 | float g_room_width_y = ROOM_WIDTH_Y; 105 | float g_room_width_z = ROOM_WIDTH_Z; 106 | 107 | float g_mic_location_x = MIC_LOCATION_X; 108 | float g_mic_location_y = MIC_LOCATION_Y; 109 | float g_mic_location_z = MIC_LOCATION_Z; 110 | float g_mic2_location_x = MIC2_LOCATION_X; 111 | float g_mic2_location_y = MIC2_LOCATION_Y; 112 | float g_mic2_location_z = MIC2_LOCATION_Z; 113 | 114 | // libsndfile 115 | SNDFILE *outfile; 116 | SF_INFO sfinfo_out; 117 | 118 | // calculate the distance (in meters) that sound will travel during one sampling interval 119 | float distance_per_sampling_interval = (float) SPEED_OF_SOUND / (float) SAMPLE_RATE; 120 | 121 | // for counting total number of rays received 122 | int numRaysReceived = 0; 123 | 124 | // struct containing room parameters 125 | typedef struct { 126 | float x_min, x_max, y_min, y_max, z_min, z_max; 127 | float color1, color2, color3; 128 | } room; 129 | 130 | // struct containing ray parameters 131 | typedef struct { 132 | float x, y, z, x_inc, y_inc, z_inc; 133 | float color1, color2, color3; 134 | bool received; 135 | float amplitude; 136 | int numReflections; 137 | } ray; 138 | 139 | // Global pointer to the room 140 | room *g_roomPtr; 141 | 142 | // Translation 143 | bool g_translate = false; 144 | 145 | // Rotation 146 | bool g_key_rotate_x = false; 147 | bool g_key_rotate_y = false; 148 | GLfloat g_inc_y = 0.0; 149 | GLfloat g_inc_x = 0.0; 150 | GLfloat scale = 1.0; 151 | GLfloat g_rotationAmt = 0.1f; 152 | static int fastRotate = 1; 153 | 154 | // Scaling 155 | bool g_key_zoomIn = false; 156 | bool g_key_zoomOut = false; 157 | 158 | // Start simulation 159 | bool g_start = false; 160 | 161 | /************************************************************************ 162 | GLOBAL VARIABLES FOR OpenGL 163 | ************************************************************************/ 164 | // width and height of the window 165 | GLsizei g_width = INIT_WIDTH; 166 | GLsizei g_height = INIT_HEIGHT; 167 | GLsizei g_last_width = INIT_WIDTH; 168 | GLsizei g_last_height = INIT_HEIGHT; 169 | 170 | static float g_ray_speed = RAY_SPEED; // initial speed of ray 171 | static int g_draw_mode = DRAW_MODE; // drawing mode 172 | 173 | GLint g_colorDirection1 = 1; // 1 = increasing; -1 = decreasing. 174 | GLint g_colorDirection2 = 1; // 1 = increasing; -1 = decreasing. 175 | GLint g_colorDirection3 = 1; // 1 = increasing; -1 = decreasing. 176 | 177 | // fill mode 178 | GLenum g_fillmode = GL_FILL; 179 | 180 | // fullscreen 181 | GLboolean g_fullscreen = false; 182 | 183 | // modelview stuff 184 | GLfloat g_linewidth = 1.0f; 185 | 186 | // array of rays to be used in the visual simulation 187 | static ray g_rays[NUM_SIM_RAYS]; 188 | 189 | // array of pointers to the rays used in the simulation 190 | ray *g_rayPtrs[NUM_SIM_RAYS]; 191 | 192 | // buffers used to store past locations of each ray (in order to create the tail effect) 193 | GLfloat *g_buffer_x[NUM_SIM_RAYS]; 194 | GLfloat *g_buffer_y[NUM_SIM_RAYS]; 195 | GLfloat *g_buffer_z[NUM_SIM_RAYS]; 196 | 197 | //----------------------------------------------------------------------------- 198 | // function prototypes 199 | //----------------------------------------------------------------------------- 200 | bool setup_output_file(); 201 | void initializeRay(ray *); 202 | void propagateRay(ray *); 203 | void checkBoundaries(ray *, room *); 204 | void checkMicrophone(ray *, float *, float *, int, int); 205 | void checkMicrophone_Visual(ray *, int); 206 | void writeToWav(float *, float *, SNDFILE *); 207 | void initializeRoom(room *); 208 | double calculate(struct rusage *, struct rusage *); 209 | bool checkInitVals(); 210 | void idleFunc( ); 211 | void displayFunc( ); 212 | void reshapeFunc( int width, int height ); 213 | void keyboardFunc( unsigned char, int, int ); 214 | void initialize_graphics(); 215 | void initialize_glut(int argc, char *argv[]); 216 | void drawRoom(room *); 217 | void rotateView(); 218 | void keyboardUpFunc(unsigned char, int, int); 219 | void drawEdge(float, float, float, float, float, float, float, room *); 220 | void drawRay(ray *, int); 221 | void drawSoundSource(); 222 | void drawMicrophones(); 223 | float power(float, int); 224 | void printInstructions(); 225 | float getScale(); 226 | void scaleView(); 227 | void printComputationTime(float, char *); 228 | void choosePreset(int); 229 | /***************************************************************************/ 230 | int main(int argc, char **argv) { 231 | int i, j; 232 | 233 | // If two arguments are specified 234 | if (argc == 2) { 235 | for (i=0; i<4;i++) { 236 | // if the argument corresponds with a preset 237 | if (atoi(argv[1]) == i) { 238 | // load that preset 239 | choosePreset(i); 240 | } 241 | } 242 | } 243 | 244 | // seed random number generator 245 | srand(time(NULL)); 246 | 247 | // Make sure all #define values make sense 248 | if (!checkInitVals()) { 249 | printf("Computation aborted.\n"); 250 | return EXIT_FAILURE; 251 | } 252 | 253 | // create and initialize room 254 | static room room1; 255 | room *roomPtr = &room1; 256 | g_roomPtr = &room1; 257 | initializeRoom(roomPtr); 258 | 259 | // If the user wants to generate an impulse and write it to a WAV file 260 | if (GENERATE_IMPULSE) { 261 | // structs for timing data 262 | struct rusage before, after, start, end; 263 | // get start time 264 | getrusage(RUSAGE_SELF, &before); 265 | // return if file cannot be opened 266 | if (!setup_output_file()) { 267 | return EXIT_FAILURE; 268 | } 269 | 270 | // create array of floats for output 271 | float *out = (float *)malloc(sizeof(float)*LENGTH); // left (mic1) 272 | float *out2 = (float *)malloc(sizeof(float)*LENGTH); // right (mic2) 273 | 274 | // fill outfile with zeros 275 | for(i = 0; i < LENGTH; i++) { 276 | out[i] = 0.0f; 277 | } 278 | initscr(); 279 | static double totalRayDuration = 0; 280 | // for each ray 281 | for(i = 0; i < NUM_RAYS; i++) { 282 | // get start time 283 | getrusage(RUSAGE_SELF, &start); 284 | // create a new ray 285 | static ray ray1; 286 | // create pointer to ray 287 | ray *rayPtr = &ray1; 288 | // initialize ray 289 | initializeRay(rayPtr); 290 | for (j = 0; j < LENGTH; j++) { 291 | // if the ray has not reached the microphone 292 | if (rayPtr->received == false) { 293 | // propogate the ray 294 | propagateRay(rayPtr); 295 | // check boundaries 296 | checkBoundaries(rayPtr, roomPtr); 297 | // check mic 298 | checkMicrophone(rayPtr, out, out2, j, i); 299 | } 300 | else { 301 | break; // move to the next ray once the current one is received 302 | } 303 | } 304 | // get end time 305 | getrusage(RUSAGE_SELF, &end); 306 | double rayDuration = calculate(&start, &end); 307 | totalRayDuration += rayDuration; 308 | clear(); 309 | printw("The simulation is %.3f percent complete (%d of %d rays computed).\n",i*100/(float)NUM_RAYS,i,NUM_RAYS); 310 | printComputationTime((totalRayDuration/i)*(NUM_RAYS - i),"remaining"); 311 | printComputationTime(totalRayDuration,"elapsed"); 312 | // printw("Remaining time: %f.\n", (totalRayDuration/i)*(NUM_RAYS - i)); 313 | refresh(); 314 | } 315 | endwin(); 316 | // write output to wav 317 | writeToWav(out, out2, outfile); 318 | 319 | if (PRINT_INFO) { 320 | // get end time 321 | getrusage(RUSAGE_SELF, &after); 322 | // calculate duration 323 | double duration = calculate(&before, &after); 324 | // print duration 325 | printf("Using %d rays, your impulse response was created in %f seconds.\n", NUM_RAYS, duration); 326 | printf("In total, %d rays were received by the virtual microphone.\n", numRaysReceived); 327 | } 328 | } 329 | 330 | // If the user wants to see a visual representation of the ray tracing 331 | if (SHOW_VISUAL) { 332 | // Initialize Glut 333 | initialize_glut(argc, argv); 334 | 335 | // set each pointer to its respective ray 336 | for (i=0;ix = SOURCE_LOCATION_X; 390 | rayPtr->y = SOURCE_LOCATION_Y; 391 | rayPtr->z = SOURCE_LOCATION_Z; 392 | 393 | // establish that each ray has not yet reached the microphone 394 | rayPtr->received = false; 395 | 396 | // set initial amplitude and number of reflections for each ray 397 | int random1 = rand()%2; 398 | float coeff; 399 | 400 | // Randomize the phase of each ray 401 | if (random1 == 0) { 402 | coeff = -1.0; 403 | } 404 | else { 405 | coeff = 1.0; 406 | } 407 | rayPtr->amplitude = coeff; 408 | rayPtr->numReflections = 0; 409 | 410 | // set the color (values only used for visual simulation) 411 | rayPtr->color1 = ((float)rand()/(float)RAND_MAX); 412 | rayPtr->color2 = ((float)rand()/(float)RAND_MAX); 413 | rayPtr->color3 = ((float)rand()/(float)RAND_MAX); 414 | 415 | // Generate initial vector for ray 416 | rayPtr->x_inc = ((float)rand()/(float)RAND_MAX - 0.5f)*0.02; 417 | rayPtr->y_inc = ((float)rand()/(float)RAND_MAX - 0.5f)*0.02; 418 | rayPtr->z_inc = ((float)rand()/(float)RAND_MAX - 0.5f)*0.02; 419 | 420 | // compute magnitude 421 | float magnitude = sqrt(rayPtr->x_inc * rayPtr->x_inc + rayPtr->y_inc * 422 | rayPtr->y_inc + rayPtr->z_inc * rayPtr->z_inc); 423 | 424 | // normalize the vector 425 | rayPtr->x_inc *= distance_per_sampling_interval/magnitude; 426 | rayPtr->y_inc *= distance_per_sampling_interval/magnitude; 427 | rayPtr->z_inc *= distance_per_sampling_interval/magnitude; 428 | } 429 | 430 | // Propagates the ray 431 | void propagateRay(ray *rayPtr) { 432 | // move the ray to its new position 433 | rayPtr->x += rayPtr->x_inc; 434 | rayPtr->y += rayPtr->y_inc; 435 | rayPtr->z += rayPtr->z_inc; 436 | } 437 | 438 | // Check to see if the ray has hit a wall 439 | void checkBoundaries(ray *rayPtr, room *room1) { 440 | // if the ray has surpassed the right wall 441 | if (rayPtr->x >= room1->x_max) { 442 | rayPtr->x_inc = -rayPtr->x_inc; 443 | rayPtr->x += rayPtr->x_inc; 444 | rayPtr->numReflections++; 445 | // printf("The right wall was hit!\n"); 446 | } 447 | // if the ray has surpassed the left wall 448 | else if (rayPtr->x <= room1->x_min) { 449 | rayPtr->x_inc = -rayPtr->x_inc; 450 | rayPtr->x += rayPtr->x_inc; 451 | rayPtr->numReflections++; 452 | // printf("The left wall was hit!\n"); 453 | } 454 | // if the ray has surpassed the ceiling 455 | else if (rayPtr->y >= room1->y_max) { 456 | rayPtr->y_inc = -rayPtr->y_inc; 457 | rayPtr->y += rayPtr->y_inc; 458 | rayPtr->numReflections++; 459 | // printf("The ceiling was hit!\n"); 460 | } 461 | // if the ray has surpassed the floor 462 | else if (rayPtr->y <= room1->y_min) { 463 | rayPtr->y_inc = -rayPtr->y_inc; 464 | rayPtr->y += rayPtr->y_inc; 465 | rayPtr->numReflections++; 466 | // printf("The floor was hit!\n"); 467 | } 468 | // if the ray has surpassed the front wall 469 | else if (rayPtr->z >= room1->z_max) { 470 | rayPtr->z_inc = -rayPtr->z_inc; 471 | rayPtr->z += rayPtr->z_inc; 472 | rayPtr->numReflections++; 473 | // printf("The front wall was hit!\n"); 474 | } 475 | // if the ray has surpassed the back wall 476 | else if (rayPtr->z <= room1->z_min) { 477 | rayPtr->z_inc = -rayPtr->z_inc; 478 | rayPtr->z += rayPtr->z_inc; 479 | rayPtr->numReflections++; 480 | // printf("The back wall was hit!\n"); 481 | } 482 | } 483 | 484 | // Check the microphone to see if the ray has been received 485 | void checkMicrophone(ray *rayPtr, float *out, float *out2, int j, int i) { 486 | 487 | int k; 488 | 489 | //If the ray has been received by the left mic 490 | if ( rayPtr->x > g_mic_location_x - MIC_WIDTH && rayPtr->x < g_mic_location_x + MIC_WIDTH 491 | && rayPtr->y > g_mic_location_y - MIC_WIDTH && rayPtr->y < g_mic_location_y + MIC_WIDTH 492 | && rayPtr->z > g_mic_location_z - MIC_WIDTH && rayPtr->z < g_mic_location_z + MIC_WIDTH) { 493 | 494 | // scale the amplitude based on how many times it reflected and the absorption coefficient 495 | rayPtr->amplitude *= power(ROOM_ABSORPTION_COEFF, rayPtr->numReflections); 496 | 497 | // print each ray received, if specified 498 | if (PRINT_RAY) { 499 | printf("Ray #%d has been received by mic #1. This ray has reflected %d times.\n", i, rayPtr->numReflections); 500 | } 501 | // if filtering is enabled 502 | if (FILTERING) { 503 | // loop to add ray to the output buffer (including filtering) 504 | for (k = 0; k < rayPtr->numReflections; k++) { 505 | // as long as the current sample position (j) plus the delay (k) is less than the buffer length 506 | if (j+k <= LENGTH) { 507 | // record ray in output buffer 508 | out[j+k] += rayPtr->amplitude; 509 | // scale the amplitude by the lowpass coefficient 510 | rayPtr->amplitude *= LOWPASS_COEFF; 511 | } 512 | } 513 | } 514 | // if filtering is not enabled 515 | else { 516 | out[j] = rayPtr->amplitude; 517 | } 518 | 519 | // stop the ray's propagation 520 | rayPtr->received = true; 521 | 522 | // update total number of rays received 523 | numRaysReceived++; 524 | } 525 | //If the ray has been received by the right mic 526 | else if ( rayPtr->x > g_mic2_location_x - MIC_WIDTH && rayPtr->x < g_mic2_location_x + MIC_WIDTH 527 | && rayPtr->y > g_mic2_location_y - MIC_WIDTH && rayPtr->y < g_mic2_location_y + MIC_WIDTH 528 | && rayPtr->z > g_mic2_location_z - MIC_WIDTH && rayPtr->z < g_mic2_location_z + MIC_WIDTH) { 529 | 530 | // scale the amplitude based on how many times it reflected and the absorption coefficient 531 | rayPtr->amplitude *= power(ROOM_ABSORPTION_COEFF, rayPtr->numReflections); 532 | 533 | // print each ray received, if specified 534 | if (PRINT_RAY) { 535 | printf("Ray #%d has been received by mic #2. This ray has reflected %d times.\n", i, rayPtr->numReflections); 536 | } 537 | // if filtering is enabled 538 | if (FILTERING) { 539 | // loop to add ray to the output buffer (including filtering) 540 | for (k = 0; k < rayPtr->numReflections; k++) { 541 | // as long as the current sample position (j) plus the delay (k) is less than the buffer length 542 | if (j+k <= LENGTH) { 543 | // record ray in output buffer 544 | out2[j+k] += rayPtr->amplitude; 545 | // scale the amplitude by the lowpass coefficient 546 | rayPtr->amplitude *= LOWPASS_COEFF; 547 | } 548 | } 549 | } 550 | // if filtering is not enabled 551 | else { 552 | out2[j] = rayPtr->amplitude; 553 | } 554 | 555 | // stop the ray's propagation 556 | rayPtr->received = true; 557 | 558 | // update total number of rays received 559 | numRaysReceived++; 560 | } 561 | } 562 | 563 | // Check to see if a ray has been received (used for the visual simulation) 564 | void checkMicrophone_Visual(ray *rayPtr, int j) { 565 | //If the ray has been received by the left mic 566 | if ( rayPtr->x > g_mic_location_x - MIC_WIDTH && rayPtr->x < g_mic_location_x + MIC_WIDTH 567 | && rayPtr->y > g_mic_location_y - MIC_WIDTH && rayPtr->y < g_mic_location_y + MIC_WIDTH 568 | && rayPtr->z > g_mic_location_z - MIC_WIDTH && rayPtr->z < g_mic_location_z + MIC_WIDTH) 569 | { 570 | // stop the ray's propagation 571 | rayPtr->received = true; 572 | if (PRINT_RAY_INFO) { 573 | printf("Ray #%d has been received by the left microphone after %d reflections!\n", j, rayPtr->numReflections); 574 | } 575 | } 576 | //If the ray has been received by the right mic 577 | else if ( rayPtr->x > g_mic2_location_x - MIC_WIDTH && rayPtr->x < g_mic2_location_x + MIC_WIDTH 578 | && rayPtr->y > g_mic2_location_y - MIC_WIDTH && rayPtr->y < g_mic2_location_y + MIC_WIDTH 579 | && rayPtr->z > g_mic2_location_z - MIC_WIDTH && rayPtr->z < g_mic2_location_z + MIC_WIDTH) 580 | { 581 | // stop the ray's propagation 582 | rayPtr->received = true; 583 | if (PRINT_RAY_INFO) { 584 | printf("Ray #%d has been received by the right microphone after %d reflections!\n", j, rayPtr->numReflections); 585 | } 586 | } 587 | } 588 | 589 | // Write output to WAV 590 | void writeToWav(float *out, float *out2, SNDFILE *outfile) { 591 | float max = 0; 592 | int i; 593 | 594 | // for output received by left mic 595 | for (i=0; i < LENGTH; i++) { 596 | // if the sample amplitude is greater than max 597 | if (fabs(out[i]) > max) { 598 | // set the max equal to this value 599 | max = fabs(out[i]); 600 | } 601 | } 602 | // for output received by right mic 603 | for (i=0; i < LENGTH; i++) { 604 | // if the sample amplitude is greater than max 605 | if (fabs(out2[i]) > max) { 606 | // set the max equal to this value 607 | max = fabs(out2[i]); 608 | } 609 | } 610 | 611 | // divide each sample by maximum value to normalize 612 | for (i=0; i < LENGTH; i++) { 613 | out[i] /= max; 614 | out2[i] /= max; 615 | } 616 | 617 | // create new buffer for stereo output 618 | float *stereo_out = (float *)malloc(sizeof(float)*LENGTH*2); 619 | 620 | // fill stereo buffer with signals from both mics 621 | for (i=0; i < LENGTH; i++) { 622 | stereo_out[2*i] = out[i]; // left mic 623 | stereo_out[2*i+1] = out2[i]; // right mic 624 | } 625 | 626 | // write to WAV file 627 | sf_writef_float(outfile, stereo_out, LENGTH); 628 | 629 | // close file 630 | sf_close(outfile); 631 | 632 | } 633 | 634 | // Initialize room parameters 635 | void initializeRoom(room *roomPtr) { 636 | // set values for min and max 637 | roomPtr->x_min = ROOM_CENTER_X - g_room_width_x/2; 638 | roomPtr->x_max = roomPtr->x_min + g_room_width_x; 639 | roomPtr->y_min = ROOM_CENTER_Y - g_room_width_y/2; 640 | roomPtr->y_max = roomPtr->y_min + g_room_width_y; 641 | roomPtr->z_min = ROOM_CENTER_Z - g_room_width_z/2; 642 | roomPtr->z_max = roomPtr->z_min + g_room_width_z; 643 | 644 | // set room color 645 | roomPtr->color1 = ((float)rand()/(float)RAND_MAX); 646 | roomPtr->color2 = ((float)rand()/(float)RAND_MAX); 647 | roomPtr->color3 = ((float)rand()/(float)RAND_MAX); 648 | } 649 | 650 | /* Returns number of seconds between b and a. */ 651 | double calculate(struct rusage *b, struct rusage *a) 652 | { 653 | if (b == NULL || a == NULL) 654 | return 0; 655 | else 656 | return ((((a->ru_utime.tv_sec * 1000000 + a->ru_utime.tv_usec) - 657 | (b->ru_utime.tv_sec * 1000000 + b->ru_utime.tv_usec)) + 658 | ((a->ru_stime.tv_sec * 1000000 + a->ru_stime.tv_usec) - 659 | (b->ru_stime.tv_sec * 1000000 + b->ru_stime.tv_usec))) 660 | / 1000000.); 661 | } 662 | 663 | /* Calculates the remaining computation time required. */ 664 | void printComputationTime(float seconds, char *string) { 665 | int minutes = (int)seconds/60; 666 | int hours = minutes/60; 667 | char *s = "s", *s1 = "s", *s2 = "s"; 668 | if (seconds < 60) { 669 | if ((int)seconds == 1) { 670 | s = ""; 671 | } else { 672 | s = "s"; 673 | } 674 | printw("Time %s: %d second%s.\n", string, (int)seconds, s); 675 | } else if (seconds < 3600) { 676 | seconds -= 60*minutes; 677 | if ((int)seconds == 1) { 678 | s = ""; 679 | } else { 680 | s = "s"; 681 | } 682 | if (minutes == 1) { 683 | s1 = ""; 684 | } else { 685 | s1 = "s"; 686 | } 687 | printw("Time %s: %d minute%s and %d second%s.\n", string, minutes, s1, (int)seconds, s); 688 | } else if (seconds < 86400) { 689 | seconds -= 60*minutes; 690 | minutes -= 60*hours; 691 | if ((int)seconds == 1) { 692 | s = ""; 693 | } else { 694 | s = "s"; 695 | } 696 | if (minutes == 1) { 697 | s1 = ""; 698 | } else { 699 | s1 = "s"; 700 | } 701 | if (hours == 1) { 702 | s2 = ""; 703 | } else { 704 | s2 = "s"; 705 | } 706 | printw("Time %s: %d hour%s, %d minute%s, and %d second%s.\n", string, hours, s2, minutes, s1, (int)seconds, s); 707 | } 708 | } 709 | 710 | /* Checks to make sure sound source, room, and microphone are set up properly */ 711 | bool checkInitVals() { 712 | bool proceed = true; 713 | // If the sound source is outside the room 714 | if (SOURCE_LOCATION_X > ROOM_CENTER_X + g_room_width_x/2 || 715 | SOURCE_LOCATION_Y > ROOM_CENTER_Y + g_room_width_y/2 || 716 | SOURCE_LOCATION_Z > ROOM_CENTER_Z + g_room_width_z/2) { 717 | printf("Make sure the source is located inside the room.\n"); 718 | proceed = false; 719 | } 720 | // If microphone 1 is outside the room 721 | if (g_mic_location_x > ROOM_CENTER_X + g_room_width_x/2 || 722 | g_mic_location_y > ROOM_CENTER_Y + g_room_width_y/2 || 723 | g_mic_location_z > ROOM_CENTER_Z + g_room_width_z/2) { 724 | printf("Make sure microphone 1 is located inside the room.\n"); 725 | proceed = false; 726 | } 727 | // If microphone 2 is outside the room 728 | if (g_mic2_location_x > ROOM_CENTER_X + g_room_width_x/2 || 729 | g_mic2_location_y > ROOM_CENTER_Y + g_room_width_y/2 || 730 | g_mic2_location_z > ROOM_CENTER_Z + g_room_width_z/2) { 731 | printf("Make sure microphone 2 is located inside the room.\n"); 732 | proceed = false; 733 | } 734 | 735 | // If the sound source is located inside the microphone 736 | if (fabs(SOURCE_LOCATION_X - g_mic_location_x) <= MIC_WIDTH/2 && 737 | fabs(SOURCE_LOCATION_Y - g_mic_location_y) <= MIC_WIDTH/2 && 738 | fabs(SOURCE_LOCATION_Z - g_mic_location_z) <= MIC_WIDTH/2) { 739 | printf("Make sure the sound source is located at a sufficient distance from mic 1.\n"); 740 | proceed = false; 741 | } 742 | // If the sound source is located inside the microphone 743 | if (fabs(SOURCE_LOCATION_X - g_mic2_location_x) <= MIC_WIDTH/2 && 744 | fabs(SOURCE_LOCATION_Y - g_mic2_location_y) <= MIC_WIDTH/2 && 745 | fabs(SOURCE_LOCATION_Z - g_mic2_location_z) <= MIC_WIDTH/2) { 746 | printf("Make sure the sound source is located at a sufficient distance from mic 2.\n"); 747 | proceed = false; 748 | } 749 | // If draw mode is not properly set 750 | if (DRAW_MODE != 0 && DRAW_MODE != 1) { 751 | printf("DRAW_MODE was set to %d. It must be set to either 0 or 1.\n", DRAW_MODE); 752 | proceed = false; 753 | } 754 | // If fade amount is not properly set 755 | if (FADE_AMT > 10) { 756 | printf("FADE_AMT was set to %d. It cannot be greater than 10.\n", FADE_AMT); 757 | proceed = false; 758 | } 759 | // If ray tail length is not properly set 760 | if (RAY_TAIL_LENGTH != 1000) { 761 | printf("RAY_TAIL_LENGTH was set to %d. It must be 1000, otherwise the program won't work.\n", RAY_TAIL_LENGTH); 762 | proceed = false; 763 | } 764 | return proceed; 765 | } 766 | 767 | //----------------------------------------------------------------------------- 768 | // Name: initialize_glut( ) 769 | // Desc: Initializes Glut with the global vars 770 | //----------------------------------------------------------------------------- 771 | void initialize_glut(int argc, char *argv[]) { 772 | // initialize GLUT 773 | glutInit( &argc, argv ); 774 | // double buffer, use rgb color, enable depth buffer 775 | glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ); 776 | // initialize the window size 777 | glutInitWindowSize( g_width, g_height ); 778 | // set the window postion 779 | glutInitWindowPosition( 400, 100 ); 780 | // create the window 781 | glutCreateWindow( "ImpulseGenerator"); 782 | // full screen 783 | if ( g_fullscreen ) glutFullScreen(); 784 | // set the idle function - called when idle 785 | glutIdleFunc( idleFunc ); 786 | // set the display function - called when redrawing 787 | glutDisplayFunc( displayFunc ); 788 | // set the reshape function - called when client area changes 789 | glutReshapeFunc( reshapeFunc ); 790 | // set the keyboard function - called on keyboard events 791 | glutKeyboardFunc( keyboardFunc ); 792 | // set the keyboard function - called on keyboard events 793 | glutKeyboardUpFunc( keyboardUpFunc ); 794 | // do our own initialization 795 | initialize_graphics( ); 796 | } 797 | 798 | //----------------------------------------------------------------------------- 799 | // Name: initialize_graphics( ) 800 | // Desc: sets initial OpenGL states and initializes any application data 801 | //----------------------------------------------------------------------------- 802 | void initialize_graphics() 803 | { 804 | glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Black Background 805 | // enable depth 806 | glEnable( GL_DEPTH_TEST ); 807 | // set fill mode 808 | glPolygonMode( GL_FRONT_AND_BACK, g_fillmode ); 809 | // line width 810 | glLineWidth( g_linewidth ); 811 | // for round points 812 | glEnable(GL_BLEND); 813 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 814 | } 815 | 816 | //----------------------------------------------------------------------------- 817 | // Name: reshapeFunc( ) 818 | // Desc: called when window size changes 819 | //----------------------------------------------------------------------------- 820 | void reshapeFunc( int w, int h ) 821 | { 822 | // save the new window size 823 | g_width = w; g_height = h; 824 | // set the matrix mode to project 825 | glMatrixMode( GL_PROJECTION ); 826 | // load the identity matrix 827 | glLoadIdentity( ); 828 | // map the view port to the client area 829 | glViewport( 0, 0, w, h ); 830 | // create the viewing frustum 831 | GLfloat fovy = 45.0f; 832 | GLfloat zNear = .05f; 833 | GLfloat zFar = 7500.0f; 834 | gluPerspective( fovy, (GLfloat) w / (GLfloat) h, zNear, zFar); 835 | // set the matrix mode to modelview 836 | glMatrixMode( GL_MODELVIEW ); 837 | // load the identity matrix 838 | glLoadIdentity( ); 839 | 840 | // position the view point 841 | // void gluLookAt( GLdouble eyeX, 842 | // GLdouble eyeY, 843 | // GLdouble eyeZ, 844 | // GLdouble centerX, 845 | // GLdouble centerY, 846 | // GLdouble centerZ, 847 | // GLdouble upX, 848 | // GLdouble upY, 849 | // GLdouble upZ ) 850 | 851 | // gluLookAt( 0.0f, 0.0f, 30.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f ); 852 | gluLookAt( 0.0f, 0.0f, h / 2.0f / tanf(fovy/2.0f), 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f ); 853 | 854 | } 855 | 856 | //----------------------------------------------------------------------------- 857 | // Name: idleFunc( ) 858 | // Desc: callback from GLUT 859 | //----------------------------------------------------------------------------- 860 | void idleFunc( ) 861 | { 862 | // render the scene 863 | glutPostRedisplay( ); 864 | } 865 | 866 | //----------------------------------------------------------------------------- 867 | // Name: keyboardFunc( ) 868 | // Desc: key event 869 | //----------------------------------------------------------------------------- 870 | void keyboardFunc( unsigned char key, int x, int y ) 871 | { 872 | int i,j; 873 | 874 | float scale = getScale(); 875 | 876 | /* calculate the value with which to scale the rotation amount. This is necessary 877 | because the rotateView() function is called every time a ray is scaled or rotated, 878 | so the rotation increment must be scaled to compensate for changes in the number 879 | of rays or the speed of the rays (which is implemented by updating the rays position 880 | more quickly). */ 881 | float scaleBy = g_rotationAmt/((float)NUM_SIM_RAYS*g_ray_speed); 882 | if (scaleBy < 0.00005) { 883 | scaleBy = 0.00005; 884 | } 885 | 886 | //printf("key: %c\n", key); 887 | switch( key ) 888 | { 889 | case '1': 890 | g_start = true; 891 | break; 892 | case ' ': 893 | fastRotate = 4; 894 | break; 895 | case 'x': 896 | g_key_zoomIn = true; // zooms in 897 | break; 898 | case 'z': 899 | g_key_zoomOut = true; // zooms out 900 | break; 901 | case '=': 902 | g_ray_speed *= RAY_SPEED_INCR; // increases ray propagation speed 903 | break; 904 | case '-': 905 | if (g_ray_speed >= 1) { 906 | g_ray_speed /= RAY_SPEED_INCR; // decreases ray propagation speed 907 | } 908 | break; 909 | case 'c': // change color of room 910 | if(g_roomPtr->color1+COLOR_INCR*2*g_colorDirection1 < 1 && g_roomPtr->color1+COLOR_INCR*2*g_colorDirection1 > 0) { 911 | g_roomPtr->color1 += COLOR_INCR * g_colorDirection1; 912 | } else { 913 | g_colorDirection1 *= -1; 914 | g_roomPtr->color1 += COLOR_INCR * g_colorDirection1; 915 | } 916 | if(g_roomPtr->color2+COLOR_INCR*2*g_colorDirection2 < 1 && g_roomPtr->color2+COLOR_INCR*2*g_colorDirection2 > 0) { 917 | g_roomPtr->color2 += COLOR_INCR * 0.83 * g_colorDirection2; 918 | } else { 919 | g_colorDirection2 *= -1; 920 | g_roomPtr->color2 += COLOR_INCR * 0.83 * g_colorDirection2; 921 | } 922 | if(g_roomPtr->color3+COLOR_INCR*2*g_colorDirection3 < 1 && g_roomPtr->color3+COLOR_INCR*2*g_colorDirection3 > 0) { 923 | g_roomPtr->color3 += COLOR_INCR * 0.73 * g_colorDirection3; 924 | } else { 925 | g_colorDirection3 *= -1; 926 | g_roomPtr->color3 += COLOR_INCR * 0.73 * g_colorDirection3; 927 | } 928 | 929 | break; 930 | case 'm': // toggle between draw modes 0 and 1 (points and line, respectively) 931 | for (i=0;ix*scale; 934 | g_buffer_y[i][j] = g_rayPtrs[i]->y*scale; 935 | g_buffer_z[i][j] = g_rayPtrs[i]->z*scale; 936 | } 937 | } 938 | if (g_draw_mode == 1) { 939 | g_draw_mode--; 940 | } else { 941 | g_draw_mode++; 942 | } 943 | // Fullscreen 944 | break; 945 | case 'f': 946 | if( !g_fullscreen ) 947 | { 948 | g_last_width = g_width; 949 | g_last_height = g_height; 950 | glutFullScreen(); 951 | } 952 | else 953 | glutReshapeWindow( g_last_width, g_last_height ); 954 | 955 | g_fullscreen = !g_fullscreen; 956 | printf("[ImpulseResponse]: fullscreen: %s\n", g_fullscreen ? "ON" : "OFF" ); 957 | break; 958 | 959 | case 'q': 960 | // Exit window 961 | exit( 0 ); 962 | break; 963 | case 'a': // Arrow key left is pressed 964 | g_inc_y = -scaleBy*(float)fastRotate; 965 | g_key_rotate_y = true; 966 | break; 967 | case 'd': // Arrow key right is pressed 968 | g_inc_y = scaleBy*(float)fastRotate; 969 | g_key_rotate_y = true; 970 | break; 971 | case 'w' : // Arrow key up is pressed 972 | g_inc_x = scaleBy*(float)fastRotate; 973 | g_key_rotate_x = true; 974 | break; 975 | case 's' : // Arrow key down is pressed 976 | g_inc_x = -scaleBy*(float)fastRotate; 977 | g_key_rotate_x = true; 978 | break; 979 | case 'p': 980 | if (g_start) { 981 | g_start = false; 982 | } else { 983 | g_start = true; 984 | } 985 | break; 986 | } 987 | } 988 | 989 | // used to stop the rotation when a key is released 990 | void keyboardUpFunc(unsigned char key, int x, int y ) { 991 | switch(key) { 992 | case 'x': 993 | g_key_zoomIn = false; 994 | break; 995 | case 'z': 996 | g_key_zoomOut = false; 997 | break; 998 | case 'a': 999 | g_key_rotate_y = false; 1000 | break; 1001 | case 'd': 1002 | g_key_rotate_y = false; 1003 | break; 1004 | case 'w': 1005 | g_key_rotate_x = false; 1006 | break; 1007 | case 's': 1008 | g_key_rotate_x = false; 1009 | break; 1010 | case ' ': 1011 | fastRotate = 1; 1012 | } 1013 | } 1014 | 1015 | //----------------------------------------------------------------------------- 1016 | // Name: displayFunc( ) 1017 | // Desc: callback function invoked to draw the client area 1018 | //----------------------------------------------------------------------------- 1019 | void displayFunc( ) 1020 | { 1021 | int i,j; 1022 | // clear the color and depth buffers 1023 | glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 1024 | drawRoom(g_roomPtr); 1025 | drawSoundSource(); 1026 | drawMicrophones(); 1027 | for (i=0;icolor1+(float)COLOR_INCR,1), fmod(roomPtr->color2+(float)COLOR_INCR,1), fmod(roomPtr->color3+(float)COLOR_INCR,1), 1); 1102 | glVertex3f(x*scale,y*scale,z*scale); 1103 | glVertex3f(x2*scale,y2*scale,z2*scale); 1104 | glEnd(); 1105 | } 1106 | glPopMatrix(); 1107 | 1108 | } 1109 | 1110 | // Draws the sound source as a point 1111 | void drawSoundSource() { 1112 | 1113 | glPointSize(POINT_SIZE*4); 1114 | glEnable(GL_POINT_SMOOTH); 1115 | glEnable(GL_BLEND); 1116 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 1117 | 1118 | glPushMatrix(); 1119 | { 1120 | rotateView(); 1121 | scaleView(); 1122 | glBegin(GL_POINTS); 1123 | glColor4f(0.2, 0.7, 0.5, 1); 1124 | glVertex3f(SOURCE_LOCATION_X, SOURCE_LOCATION_Y, SOURCE_LOCATION_Z); 1125 | glEnd(); 1126 | } 1127 | glPopMatrix(); 1128 | } 1129 | 1130 | // Draws the room by drawing each of the edges 1131 | void drawRoom(room *roomPtr) { 1132 | 1133 | float scale = getScale(); 1134 | // Draw the edges of the room 1135 | drawEdge(roomPtr->x_min, roomPtr->y_min, roomPtr->z_min, 1136 | roomPtr->x_max, roomPtr->y_min, roomPtr->z_min, scale, roomPtr); 1137 | 1138 | drawEdge(roomPtr->x_min, roomPtr->y_min, roomPtr->z_min, 1139 | roomPtr->x_min, roomPtr->y_min, roomPtr->z_max, scale, roomPtr); 1140 | 1141 | drawEdge(roomPtr->x_min, roomPtr->y_min, roomPtr->z_min, 1142 | roomPtr->x_min, roomPtr->y_max, roomPtr->z_min, scale, roomPtr); 1143 | 1144 | drawEdge(roomPtr->x_min, roomPtr->y_max, roomPtr->z_min, 1145 | roomPtr->x_min, roomPtr->y_max, roomPtr->z_max, scale, roomPtr); 1146 | 1147 | drawEdge(roomPtr->x_min, roomPtr->y_max, roomPtr->z_min, 1148 | roomPtr->x_max, roomPtr->y_max, roomPtr->z_min, scale, roomPtr); 1149 | 1150 | drawEdge(roomPtr->x_min, roomPtr->y_max, roomPtr->z_max, 1151 | roomPtr->x_min, roomPtr->y_min, roomPtr->z_max, scale, roomPtr); 1152 | 1153 | drawEdge(roomPtr->x_min, roomPtr->y_max, roomPtr->z_max, 1154 | roomPtr->x_max, roomPtr->y_max, roomPtr->z_max, scale, roomPtr); 1155 | 1156 | drawEdge(roomPtr->x_max, roomPtr->y_min, roomPtr->z_max, 1157 | roomPtr->x_min, roomPtr->y_min, roomPtr->z_max, scale, roomPtr); 1158 | 1159 | drawEdge(roomPtr->x_max, roomPtr->y_min, roomPtr->z_max, 1160 | roomPtr->x_max, roomPtr->y_min, roomPtr->z_min, scale, roomPtr); 1161 | 1162 | drawEdge(roomPtr->x_max, roomPtr->y_min, roomPtr->z_max, 1163 | roomPtr->x_max, roomPtr->y_max, roomPtr->z_max, scale, roomPtr); 1164 | 1165 | drawEdge(roomPtr->x_max, roomPtr->y_max, roomPtr->z_min, 1166 | roomPtr->x_max, roomPtr->y_min, roomPtr->z_min, scale, roomPtr); 1167 | 1168 | drawEdge(roomPtr->x_max, roomPtr->y_max, roomPtr->z_min, 1169 | roomPtr->x_max, roomPtr->y_max, roomPtr->z_max, scale, roomPtr); 1170 | 1171 | } 1172 | 1173 | // Draws the microphones as points 1174 | void drawMicrophones() { 1175 | 1176 | float scale = getScale(); 1177 | glPointSize(POINT_SIZE*4); 1178 | glEnable(GL_POINT_SMOOTH); 1179 | glEnable(GL_BLEND); 1180 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 1181 | 1182 | glPushMatrix(); 1183 | { 1184 | rotateView(); 1185 | scaleView(); 1186 | glBegin(GL_POINTS); 1187 | glColor4f(0.9, 0.1, 0.4, 1); 1188 | glVertex3f(g_mic_location_x*scale, g_mic_location_y*scale, g_mic_location_z*scale); 1189 | glEnd(); 1190 | } 1191 | glPopMatrix(); 1192 | 1193 | glPushMatrix(); 1194 | { 1195 | rotateView(); 1196 | scaleView(); 1197 | glBegin(GL_POINTS); 1198 | glColor4f(0.9, 0.1, 0.4, 1); 1199 | glVertex3f(g_mic2_location_x*scale, g_mic2_location_y*scale, g_mic2_location_z*scale); 1200 | glEnd(); 1201 | } 1202 | glPopMatrix(); 1203 | 1204 | } 1205 | 1206 | // Draws a ray either as a point (if draw mode is 0) or as a line (if draw mode is 1) 1207 | void drawRay(ray *rayPtr, int j) { 1208 | int i; 1209 | 1210 | float scale = getScale(); 1211 | 1212 | // used to decrease opacity over time if absorption is included as a simulation parameter 1213 | static float absorption = 1; 1214 | 1215 | // If point mode is selected 1216 | if (g_draw_mode == 0) { 1217 | 1218 | glPointSize(POINT_SIZE); 1219 | glEnable(GL_POINT_SMOOTH); 1220 | glEnable(GL_BLEND); 1221 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 1222 | 1223 | glPushMatrix(); 1224 | { 1225 | rotateView(); 1226 | scaleView(); 1227 | glBegin(GL_POINTS); 1228 | if (SHOW_ABSORPTION) { 1229 | absorption = power((float)ROOM_ABSORPTION_COEFF, rayPtr->numReflections); 1230 | } 1231 | glColor4f(rayPtr->color1, rayPtr->color2, rayPtr->color3, 1*absorption); 1232 | 1233 | glVertex3f(rayPtr->x*scale, rayPtr->y*scale, rayPtr->z*scale); 1234 | if (rayPtr->received == false && g_start) { 1235 | propagateRay(rayPtr); 1236 | checkBoundaries(rayPtr, g_roomPtr); 1237 | checkMicrophone_Visual(rayPtr, j); 1238 | } 1239 | glEnd(); 1240 | } 1241 | glPopMatrix(); 1242 | } 1243 | // If line mode is selected 1244 | else if (g_draw_mode == 1) { 1245 | // update the buffers, propagate the ray 1246 | if (rayPtr->received == false && g_start) { 1247 | // shift the values in each array back one position 1248 | for (i=0; i < RAY_TAIL_LENGTH; i++) { 1249 | g_buffer_x[j][RAY_TAIL_LENGTH-i] = g_buffer_x[j][RAY_TAIL_LENGTH-i-1]; 1250 | g_buffer_y[j][RAY_TAIL_LENGTH-i] = g_buffer_y[j][RAY_TAIL_LENGTH-i-1]; 1251 | g_buffer_z[j][RAY_TAIL_LENGTH-i] = g_buffer_z[j][RAY_TAIL_LENGTH-i-1]; 1252 | } 1253 | g_buffer_x[j][0] = rayPtr->x*scale; // the first position of each array is the current location 1254 | g_buffer_y[j][0] = rayPtr->y*scale; 1255 | g_buffer_z[j][0] = rayPtr->z*scale; 1256 | propagateRay(rayPtr); 1257 | checkBoundaries(rayPtr, g_roomPtr); 1258 | checkMicrophone_Visual(rayPtr, j); 1259 | } 1260 | // draw the ray 1261 | glPushMatrix(); 1262 | { 1263 | rotateView(); 1264 | scaleView(); 1265 | glBegin(GL_LINE_STRIP); 1266 | for (i=0;inumReflections); 1270 | } 1271 | 1272 | glColor4f(rayPtr->color1, rayPtr->color2, rayPtr->color3, scaleFactor*absorption); 1273 | glLineWidth(7*scaleFactor); 1274 | 1275 | glVertex3f(g_buffer_x[j][i], g_buffer_y[j][i], g_buffer_z[j][i]); 1276 | } 1277 | glEnd(); 1278 | } 1279 | glPopMatrix(); 1280 | } 1281 | 1282 | } 1283 | 1284 | // calculates the power given a base and exponent 1285 | float power(float base, int pow) { 1286 | if (pow == 0) { 1287 | return 1; 1288 | } else if (pow == 1) { 1289 | return base; 1290 | } 1291 | return base * power(base, pow-1); 1292 | } 1293 | 1294 | // prints instructions for the visual simulation 1295 | void printInstructions() 1296 | { 1297 | printf( "----------------------------------------------------\n" ); 1298 | printf( "Impulse Response Simulator\n" ); 1299 | printf( "by Aaron Dawson, 2014\n" ); 1300 | printf( "New York University\n" ); 1301 | printf( "----------------------------------------------------\n" ); 1302 | printf( "'1' - start simulation\n" ); 1303 | printf( "'f' - toggle fullscreen\n" ); 1304 | printf( "'=/-' - change ray propagation speed\n" ); 1305 | printf( "'z/x' - zoom\n" ); 1306 | printf( "'a/d/w/s' - rotate view\n" ); 1307 | printf( "'spacebar' - faster rotation\n" ); 1308 | printf( "'c' - change room color\n" ); 1309 | printf( "'m' - change draw mode\n" ); 1310 | printf( "'p' - pause\n" ); 1311 | printf( "'q' - quit\n" ); 1312 | printf( "----------------------------------------------------\n" ); 1313 | printf( "\n" ); 1314 | } 1315 | 1316 | /* Function to get scaling factor for use in setting default sizes. Thus, 1317 | the room will always be initialized to appropriate size on the screen 1318 | regardless of what its actual size is. In other words, a room that is 1319 | 3x4x5 will appear just as large as a room that is 30x40x50, and all other 1320 | objects on the screen will be scaled accordingly. */ 1321 | float getScale() { 1322 | // determine scaling factor 1323 | float max = g_room_width_x; 1324 | if (g_room_width_y > max) { 1325 | max = g_room_width_y; 1326 | } 1327 | if (g_room_width_z > max) { 1328 | max = g_room_width_z; 1329 | } 1330 | float scale = (float)SCALE/max; 1331 | 1332 | return scale; 1333 | } 1334 | 1335 | // initializes a preset 1336 | void choosePreset(int i) { 1337 | switch ( i ) 1338 | { 1339 | case 0: 1340 | g_room_width_x = 0.5; 1341 | g_room_width_y = 0.4; 1342 | g_room_width_z = 0.3; 1343 | g_mic_location_x = 0.2; 1344 | g_mic_location_y = 0.03; 1345 | g_mic_location_z = 0.02; 1346 | g_mic2_location_x = -0.2; 1347 | g_mic2_location_y = 0.03; 1348 | g_mic2_location_z = 0.02; 1349 | 1350 | break; 1351 | case 1: 1352 | g_room_width_x = 10; 1353 | g_room_width_y = 1.5; 1354 | g_room_width_z = 2; 1355 | break; 1356 | case 2: 1357 | g_room_width_x = 50; 1358 | g_room_width_y = 20; 1359 | g_room_width_z = 30; 1360 | g_mic_location_x = 20; 1361 | g_mic_location_y = 0.0; 1362 | g_mic_location_z = 0.2; 1363 | g_mic2_location_x = 20; 1364 | g_mic2_location_y = 0.0; 1365 | g_mic2_location_z = -0.2; 1366 | break; 1367 | case 3: 1368 | g_room_width_x = 10; 1369 | g_room_width_y = 3; 1370 | g_room_width_z = 15; 1371 | break; 1372 | } 1373 | } 1374 | -------------------------------------------------------------------------------- /generateImpulse.dSYM/Contents/Info (2).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleIdentifier 8 | com.apple.xcode.dsym.generateImpulse 9 | CFBundleInfoDictionaryVersion 10 | 6.0 11 | CFBundlePackageType 12 | dSYM 13 | CFBundleSignature 14 | ???? 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleVersion 18 | 1 19 | 20 | 21 | -------------------------------------------------------------------------------- /generateImpulse.dSYM/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleIdentifier 8 | com.apple.xcode.dsym.generateImpulse 9 | CFBundleInfoDictionaryVersion 10 | 6.0 11 | CFBundlePackageType 12 | dSYM 13 | CFBundleSignature 14 | ???? 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleVersion 18 | 1 19 | 20 | 21 | -------------------------------------------------------------------------------- /generateImpulse.dSYM/Contents/Resources/DWARF/generateImpulse: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Add9Sus4/Ray-Tracing-Impulse-Response-Generator/01e3dd3cf079dd8cae2005f525bf070bcf6e9de9/generateImpulse.dSYM/Contents/Resources/DWARF/generateImpulse -------------------------------------------------------------------------------- /generateImpulse.dSYM/Contents/Resources/DWARF/generateImpulse (2): -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Add9Sus4/Ray-Tracing-Impulse-Response-Generator/01e3dd3cf079dd8cae2005f525bf070bcf6e9de9/generateImpulse.dSYM/Contents/Resources/DWARF/generateImpulse (2) -------------------------------------------------------------------------------- /impulse.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Add9Sus4/Ray-Tracing-Impulse-Response-Generator/01e3dd3cf079dd8cae2005f525bf070bcf6e9de9/impulse.wav -------------------------------------------------------------------------------- /ss2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Add9Sus4/Ray-Tracing-Impulse-Response-Generator/01e3dd3cf079dd8cae2005f525bf070bcf6e9de9/ss2.png --------------------------------------------------------------------------------