LCOV - code coverage report
Current view: top level - compositor - mpeg4_sound.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 129 134 96.3 %
Date: 2021-04-29 23:48:07 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2012
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / Scene Compositor sub-project
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : 
      27             : 
      28             : #include "nodes_stacks.h"
      29             : #include "visual_manager.h"
      30             : 
      31             : #ifndef GPAC_DISABLE_VRML
      32             : 
      33             : typedef struct
      34             : {
      35             :         GF_SoundInterface snd_ifce;
      36             :         SFVec3f pos;
      37             : } Sound2DStack;
      38             : 
      39             : /*sound2D wraper - spacialization is not supported yet*/
      40        2978 : static void TraverseSound2D(GF_Node *node, void *rs, Bool is_destroy)
      41             : {
      42             :         GF_TraverseState *tr_state = (GF_TraverseState*) rs;
      43             :         M_Sound2D *snd = (M_Sound2D *)node;
      44        2978 :         Sound2DStack *st = (Sound2DStack *)gf_node_get_private(node);
      45             : 
      46        2978 :         if (is_destroy) {
      47         228 :                 gf_free(st);
      48         228 :                 return;
      49             :         }
      50        2750 :         if (!snd->source) return;
      51             : 
      52             :         /*this implies no DEF/USE for real location...*/
      53        2750 :         st->pos.x = snd->location.x;
      54        2750 :         st->pos.y = snd->location.y;
      55        2750 :         st->pos.z = 0;
      56             : #ifndef GPAC_DISABLE_3D
      57        2750 :         if (tr_state->visual->type_3d)
      58         242 :                 gf_mx_apply_vec(&tr_state->model_matrix, &st->pos);
      59             :         else
      60             : #endif
      61        2508 :                 gf_mx2d_apply_coords(&tr_state->transform, &st->pos.x, &st->pos.y);
      62             : 
      63             : 
      64        2750 :         tr_state->sound_holder = &st->snd_ifce;
      65        2750 :         gf_node_traverse((GF_Node *) snd->source, tr_state);
      66        2750 :         tr_state->sound_holder = NULL;
      67             :         /*never cull Sound2d*/
      68        2750 :         tr_state->disable_cull = 1;
      69             : }
      70       18221 : static Bool SND2D_GetChannelVolume(GF_Node *node, Fixed *vol)
      71             : {
      72             :         u32 i;
      73       18221 :         Fixed volume = ((M_Sound2D *)node)->intensity;
      74      455525 :         for (i=0; i<GF_AUDIO_MIXER_MAX_CHANNELS; i++) {
      75      437304 :                 vol[i] = volume;
      76             :         }
      77       18221 :         return (volume==FIX_ONE) ? 0 : 1;
      78             : }
      79             : 
      80             : 
      81         228 : void compositor_init_sound2d(GF_Compositor *compositor, GF_Node *node)
      82             : {
      83             :         Sound2DStack *snd;
      84         228 :         GF_SAFEALLOC(snd, Sound2DStack);
      85         228 :         if (!snd) {
      86           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate sound 2d stack\n"));
      87             :                 return;
      88             :         }
      89         228 :         snd->snd_ifce.GetChannelVolume = SND2D_GetChannelVolume;
      90         228 :         snd->snd_ifce.owner = node;
      91         228 :         gf_node_set_private(node, snd);
      92         228 :         gf_node_set_callback_function(node, TraverseSound2D);
      93             : }
      94             : 
      95             : #ifndef GPAC_DISABLE_3D
      96             : 
      97           2 : static Fixed snd_compute_gain(Fixed min_b, Fixed min_f, Fixed max_b, Fixed max_f, SFVec3f pos)
      98             : {
      99             :         Fixed sqpos_x, sqpos_z;
     100             :         Fixed y_pos, x_pos, dist_ellip, viewp_dist, dist_from_foci_min, dist_from_foci_max, d_min, d_max, sqb_min, sqb_max;
     101           2 :         Fixed a_in = (min_f+min_b)/2;
     102           2 :         Fixed b_in = gf_sqrt(gf_mulfix(min_b, min_f));
     103           2 :         Fixed alpha_min = (min_f-min_b)/2;
     104             :         Fixed dist_foci_min = (min_f-min_b);
     105           2 :         Fixed a_out = (max_f+max_b)/2;  //first ellipse axis
     106           2 :         Fixed b_out = gf_sqrt(gf_mulfix(max_b, max_f));
     107           2 :         Fixed alpha_max = (max_f-max_b)/2; //origo from focus
     108             :         Fixed dist_foci_max = (max_f-max_b);
     109             :         Fixed x_min = 0;
     110             :         Fixed x_max = 0;
     111             :         Fixed y_min = 0;
     112             :         Fixed y_max = 0;
     113           2 :         Fixed k = (ABS(pos.z) >= FIX_EPSILON) ? gf_divfix(pos.x, pos.z) : 0;
     114             : 
     115           2 :         sqpos_x = gf_mulfix(pos.x, pos.x);
     116           2 :         sqpos_z = gf_mulfix(pos.z, pos.z);
     117             : 
     118           2 :         dist_from_foci_min = gf_sqrt(sqpos_z + sqpos_x) + gf_sqrt( gf_mulfix(pos.z - dist_foci_min, pos.z - dist_foci_min) + sqpos_x);
     119           2 :         dist_from_foci_max = gf_sqrt(sqpos_z + sqpos_x) + gf_sqrt( gf_mulfix(pos.z - dist_foci_max, pos.z - dist_foci_max) + sqpos_x);
     120             :         d_min = min_f+min_b;
     121             :         d_max = max_f+max_b;
     122           2 :         if(dist_from_foci_max > d_max) return 0;
     123           2 :         else if (dist_from_foci_min <= d_min) return FIX_ONE;
     124             : 
     125           2 :         sqb_min = gf_mulfix(b_in, b_in);
     126           2 :         sqb_max = gf_mulfix(b_out, b_out);
     127             : 
     128           2 :         if (ABS(pos.z) > FIX_ONE/10000) {
     129           2 :                 s32 sign = (pos.z>0) ? 1 : -1;
     130             :                 Fixed a_in_k_sq, a_out_k_sq;
     131           2 :                 a_in_k_sq = gf_mulfix(a_in, k);
     132           2 :                 a_in_k_sq = gf_mulfix(a_in_k_sq, a_in_k_sq);
     133             : 
     134           2 :                 x_min = gf_mulfix(alpha_min, sqb_min) + sign*gf_mulfix( gf_mulfix(a_in, b_in), gf_sqrt(a_in_k_sq + sqb_min - gf_mulfix( gf_mulfix(alpha_min, k), gf_mulfix(alpha_min, k))));
     135           2 :                 x_min = gf_divfix(x_min, sqb_min + a_in_k_sq);
     136           2 :                 y_min = gf_mulfix(k, x_min);
     137             : 
     138           2 :                 a_out_k_sq = gf_mulfix(a_out, k);
     139           2 :                 a_out_k_sq = gf_mulfix(a_out_k_sq, a_out_k_sq);
     140             : 
     141           2 :                 x_max = gf_mulfix(alpha_max, sqb_max) + sign*gf_mulfix( gf_mulfix(a_out, b_out), gf_sqrt( a_out_k_sq + sqb_max - gf_mulfix( gf_mulfix(alpha_max, k), gf_mulfix(alpha_max, k))));
     142           2 :                 x_max = gf_divfix(x_max, sqb_max + a_out_k_sq);
     143           2 :                 y_max = gf_mulfix(k, x_max);
     144             :         } else {
     145             :                 x_min = x_max = 0;
     146           0 :                 y_min = gf_mulfix(b_in, gf_sqrt(FIX_ONE - gf_mulfix( gf_divfix(alpha_min,a_in), gf_divfix(alpha_min,a_in)) ) );
     147           0 :                 y_max = gf_mulfix(b_out, gf_sqrt(FIX_ONE - gf_mulfix( gf_divfix(alpha_max,a_out), gf_divfix(alpha_max,a_out)) ) );
     148             :         }
     149             : 
     150           2 :         y_pos = gf_sqrt(sqpos_x) - y_min;
     151           2 :         x_pos = pos.z - x_min;
     152           2 :         x_max -= x_min;
     153           2 :         y_max -= y_min;
     154           2 :         dist_ellip = gf_sqrt( gf_mulfix(y_max, y_max) + gf_mulfix(x_max, x_max));
     155           2 :         viewp_dist = gf_sqrt( gf_mulfix(y_pos, y_pos) + gf_mulfix(x_pos, x_pos));
     156           2 :         viewp_dist = gf_divfix(viewp_dist, dist_ellip);
     157             : 
     158           2 :         return FLT2FIX ( (Float) pow(10.0,- FIX2FLT(viewp_dist)));
     159             : }
     160             : 
     161             : 
     162             : typedef struct
     163             : {
     164             :         GF_SoundInterface snd_ifce;
     165             :         GF_Matrix mx;
     166             :         SFVec3f last_pos;
     167             :         Bool identity;
     168             :         /*local system*/
     169             :         Fixed intensity;
     170             :         Fixed lgain, rgain;
     171             : } SoundStack;
     172             : 
     173         652 : static void TraverseSound(GF_Node *node, void *rs, Bool is_destroy)
     174             : {
     175             :         GF_TraverseState *tr_state = (GF_TraverseState*) rs;
     176             :         M_Sound *snd = (M_Sound *)node;
     177         652 :         SoundStack *st = (SoundStack *)gf_node_get_private(node);
     178             : 
     179         652 :         if (is_destroy) {
     180           2 :                 gf_free(st);
     181           2 :                 return;
     182             :         }
     183         650 :         if (!snd->source) return;
     184             : 
     185         650 :         tr_state->sound_holder = &st->snd_ifce;
     186             : 
     187             :         /*forward in case we're switched off*/
     188         650 :         if (tr_state->switched_off) {
     189           0 :                 gf_node_traverse((GF_Node *) snd->source, tr_state);
     190             :         }
     191         650 :         else if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
     192             :                 /*we can't cull sound since*/
     193           2 :                 tr_state->disable_cull = 1;
     194         648 :         } else if (tr_state->traversing_mode==TRAVERSE_SORT) {
     195             :                 GF_Matrix mx;
     196             :                 SFVec3f usr, snd_dir, pos;
     197             :                 Fixed mag, ang;
     198             :                 /*this implies no DEF/USE for real location...*/
     199         302 :                 gf_mx_copy(st->mx, tr_state->model_matrix);
     200             :                 gf_mx_copy(mx, tr_state->model_matrix);
     201         302 :                 gf_mx_inverse(&mx);
     202             : 
     203         302 :                 snd_dir = snd->direction;
     204         302 :                 gf_vec_norm(&snd_dir);
     205             : 
     206             :                 /*get user location*/
     207         302 :                 usr = tr_state->camera->position;
     208         302 :                 gf_mx_apply_vec(&mx, &usr);
     209             : 
     210             :                 /*recenter to ellipse focal*/
     211         302 :                 gf_vec_diff(usr, usr, snd->location);
     212         302 :                 mag = gf_vec_len(usr);
     213         302 :                 if (!mag) mag = FIX_ONE/10;
     214         302 :                 ang = gf_divfix(gf_vec_dot(snd_dir, usr), mag);
     215             : 
     216         302 :                 usr.z = gf_mulfix(ang, mag);
     217         302 :                 usr.x = gf_sqrt(gf_mulfix(mag, mag) - gf_mulfix(usr.z, usr.z));
     218         302 :                 usr.y = 0;
     219         302 :                 if (!gf_vec_equal(usr, st->last_pos)) {
     220           2 :                         st->intensity = snd_compute_gain(snd->minBack, snd->minFront, snd->maxBack, snd->maxFront, usr);
     221           2 :                         st->intensity = gf_mulfix(st->intensity, snd->intensity);
     222           2 :                         st->last_pos = usr;
     223             :                 }
     224         302 :                 st->identity = (st->intensity==FIX_ONE) ? 1 : 0;
     225             : 
     226         302 :                 if (snd->spatialize) {
     227             :                         Fixed sign;
     228             :                         SFVec3f cross;
     229         151 :                         pos = snd->location;
     230         151 :                         gf_mx_apply_vec(&tr_state->model_matrix, &pos);
     231         151 :                         gf_vec_diff(pos, pos, tr_state->camera->position);
     232         151 :                         gf_vec_diff(usr, tr_state->camera->target, tr_state->camera->position);
     233         151 :                         gf_vec_norm(&pos);
     234         151 :                         gf_vec_norm(&usr);
     235             : 
     236         151 :                         ang = gf_acos(gf_vec_dot(usr, pos));
     237             :                         /*get orientation*/
     238         151 :                         cross = gf_vec_cross(usr, pos);
     239         151 :                         sign = gf_vec_dot(cross, tr_state->camera->up);
     240         151 :                         if (sign>0) ang *= -1;
     241         151 :                         ang = (FIX_ONE + gf_sin(ang)) / 2;
     242         151 :                         st->lgain = (FIX_ONE - gf_mulfix(ang, ang));
     243         151 :                         st->rgain = FIX_ONE - gf_mulfix(FIX_ONE - ang, FIX_ONE - ang);
     244             :                         /*renorm between 0 and 1*/
     245         151 :                         st->lgain = gf_mulfix(st->lgain, 4*st->intensity/3);
     246         151 :                         st->rgain = gf_mulfix(st->rgain, 4*st->intensity/3);
     247             : 
     248         151 :                         if (st->identity && ((st->lgain!=FIX_ONE) || (st->rgain!=FIX_ONE))) st->identity = 0;
     249             :                 } else {
     250         151 :                         st->lgain = st->rgain = FIX_ONE;
     251             :                 }
     252         302 :                 gf_node_traverse((GF_Node *) snd->source, tr_state);
     253             :         }
     254             : 
     255         650 :         tr_state->sound_holder = NULL;
     256             : }
     257       15798 : static Bool SND_GetChannelVolume(GF_Node *node, Fixed *vol)
     258             : {
     259             :         u32 i;
     260             :         M_Sound *snd = (M_Sound *)node;
     261       15798 :         SoundStack *st = (SoundStack *)gf_node_get_private(node);
     262      363354 :         for (i=2; i<GF_AUDIO_MIXER_MAX_CHANNELS; i++)
     263      347556 :                 vol[i] = st->intensity;
     264             : 
     265       15798 :         if (snd->spatialize) {
     266        7899 :                 vol[0] = st->lgain;
     267        7899 :                 vol[1] = st->rgain;
     268             :         } else {
     269        7899 :                 vol[0] = vol[1] = st->intensity;
     270             :         }
     271       15798 :         return !st->identity;
     272             : }
     273             : 
     274           2 : void compositor_init_sound(GF_Compositor *compositor, GF_Node *node)
     275             : {
     276             :         SoundStack *snd;
     277           2 :         GF_SAFEALLOC(snd, SoundStack);
     278           2 :         if (!snd) {
     279           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate sound stack\n"));
     280             :                 return;
     281             :         }
     282           2 :         snd->snd_ifce.GetChannelVolume = SND_GetChannelVolume;
     283           2 :         snd->snd_ifce.owner = node;
     284           2 :         gf_node_set_private(node, snd);
     285           2 :         gf_node_set_callback_function(node, TraverseSound);
     286             : }
     287             : 
     288             : #endif /*GPAC_DISABLE_3D*/
     289             : 
     290             : #endif /*GPAC_DISABLE_VRML*/

Generated by: LCOV version 1.13