src/object/ambient_sound.cpp

Go to the documentation of this file.
00001 //  SuperTux
00002 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
00003 //
00004 //  This program is free software: you can redistribute it and/or modify
00005 //  it under the terms of the GNU General Public License as published by
00006 //  the Free Software Foundation, either version 3 of the License, or
00007 //  (at your option) any later version.
00008 //
00009 //  This program is distributed in the hope that it will be useful,
00010 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 //  GNU General Public License for more details.
00013 //
00014 //  You should have received a copy of the GNU General Public License
00015 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016 
00017 #include <limits>
00018 #include <math.h>
00019 
00020 #include "audio/sound_manager.hpp"
00021 #include "audio/sound_source.hpp"
00022 #include "object/ambient_sound.hpp"
00023 #include "object/camera.hpp"
00024 #include "scripting/squirrel_util.hpp"
00025 #include "supertux/object_factory.hpp"
00026 #include "supertux/sector.hpp"
00027 #include "util/reader.hpp"
00028 
00029 AmbientSound::AmbientSound(const Reader& lisp) :
00030   name(),
00031   position(),
00032   dimension(),
00033   sample(),
00034   sound_source(),
00035   latency(),
00036   distance_factor(),
00037   distance_bias(),
00038   silence_distance(),
00039   maximumvolume(),
00040   targetvolume(),
00041   currentvolume(),
00042   volume_ptr()
00043 {
00044   name="";
00045   position.x = 0;
00046   position.y = 0;
00047 
00048   dimension.x = 0;
00049   dimension.y = 0;
00050 
00051   distance_factor = 0;
00052   distance_bias = 0;
00053   maximumvolume = 1;
00054   sample = "";
00055   currentvolume = 0;
00056 
00057   if (!(lisp.get("x", position.x)&&lisp.get("y", position.y))) {
00058     log_warning << "No Position in ambient_sound" << std::endl;
00059   }
00060 
00061   lisp.get("name" , name);
00062   lisp.get("width" , dimension.x);
00063   lisp.get("height", dimension.y);
00064 
00065   lisp.get("distance_factor",distance_factor);
00066   lisp.get("distance_bias"  ,distance_bias  );
00067   lisp.get("sample"         ,sample         );
00068   lisp.get("volume"         ,maximumvolume  );
00069 
00070   // set dimension to zero if smaller than 64, which is default size in flexlay
00071 
00072   if ((dimension.x <= 64) || (dimension.y <= 64)) {
00073     dimension.x = 0;
00074     dimension.y = 0;
00075   }
00076 
00077   // square all distances (saves us a sqrt later)
00078 
00079   distance_bias*=distance_bias;
00080   distance_factor*=distance_factor;
00081 
00082   // set default silence_distance
00083 
00084   if (distance_factor == 0)
00085     silence_distance = std::numeric_limits<float>::max();
00086   else
00087     silence_distance = 1/distance_factor;
00088 
00089   lisp.get("silence_distance",silence_distance);
00090 
00091   sound_source = 0; // not playing at the beginning
00092   sound_manager->preload(sample);
00093   latency=0;
00094 }
00095 
00096 AmbientSound::AmbientSound(Vector pos, float factor, float bias, float vol, std::string file) :
00097   name(),
00098   position(),
00099   dimension(),
00100   sample(),
00101   sound_source(),
00102   latency(),
00103   distance_factor(),
00104   distance_bias(),
00105   silence_distance(),
00106   maximumvolume(),
00107   targetvolume(),
00108   currentvolume(),
00109   volume_ptr()
00110 {
00111   position.x=pos.x;
00112   position.y=pos.y;
00113 
00114   dimension.x=0;
00115   dimension.y=0;
00116 
00117   distance_factor=factor*factor;
00118   distance_bias=bias*bias;
00119   maximumvolume=vol;
00120   sample=file;
00121 
00122   // set default silence_distance
00123 
00124   if (distance_factor == 0)
00125     silence_distance = std::numeric_limits<float>::max();
00126   else
00127     silence_distance = 1/distance_factor;
00128 
00129   sound_source = 0; // not playing at the beginning
00130   sound_manager->preload(sample);
00131   latency=0;
00132 }
00133 
00134 AmbientSound::~AmbientSound()
00135 {
00136   stop_playing();
00137 }
00138 
00139 void
00140 AmbientSound::hit(Player& )
00141 {
00142 }
00143 
00144 void
00145 AmbientSound::stop_playing() 
00146 {
00147   delete sound_source;
00148   sound_source = 0;
00149 }
00150 
00151 void
00152 AmbientSound::start_playing()
00153 {
00154   try {
00155     sound_source = sound_manager->create_sound_source(sample);
00156     if(!sound_source)
00157       throw std::runtime_error("file not found");
00158 
00159     sound_source->set_gain(0);
00160     sound_source->set_looping(true);
00161     currentvolume=targetvolume=1e-20f;
00162     sound_source->play();
00163   } catch(std::exception& e) {
00164     log_warning << "Couldn't play '" << sample << "': " << e.what() << "" << std::endl;
00165     delete sound_source;
00166     sound_source = 0;
00167     remove_me();
00168   }
00169 }
00170 
00171 void
00172 AmbientSound::update(float deltat)
00173 {
00174   if (latency-- <= 0) {
00175     float px,py;
00176     float rx,ry;
00177 
00178     if (!Sector::current() || !Sector::current()->camera) return;
00179     // Camera position
00180     px=Sector::current()->camera->get_center().x;
00181     py=Sector::current()->camera->get_center().y;
00182 
00183     // Relate to which point in the area
00184     rx=px<position.x?position.x:
00185       (px<position.x+dimension.x?px:position.x+dimension.x);
00186     ry=py<position.y?position.y:
00187       (py<position.y+dimension.y?py:position.y+dimension.y);
00188 
00189     // calculate square of distance
00190     float sqrdistance=(px-rx)*(px-rx)+(py-ry)*(py-ry);
00191     sqrdistance-=distance_bias;
00192 
00193     // inside the bias: full volume (distance 0)
00194     if (sqrdistance<0)
00195       sqrdistance=0;
00196 
00197     // calculate target volume - will never become 0
00198     targetvolume=1/(1+sqrdistance*distance_factor);
00199     float rise=targetvolume/currentvolume;
00200 
00201     // rise/fall half life?
00202     currentvolume*=pow(rise,deltat*10);
00203     currentvolume += 1e-6f; // volume is at least 1e-6 (0 would never rise)
00204 
00205     if (sound_source != 0) {
00206 
00207       // set the volume
00208       sound_source->set_gain(currentvolume*maximumvolume);
00209 
00210       if (sqrdistance>=silence_distance && currentvolume<1e-3)
00211         stop_playing();
00212       latency=0;
00213     } else {
00214       if (sqrdistance<silence_distance) {
00215         start_playing();
00216         latency=0;
00217       }
00218       else // set a reasonable latency
00219         latency=(int)(0.001/distance_factor);
00220       //(int)(10*((sqrdistance-silence_distance)/silence_distance));
00221     }
00222   }
00223 
00224   // heuristically measured "good" latency maximum
00225 
00226   //  if (latency>0.001/distance_factor)
00227   // latency=
00228 }
00229 
00230 void
00231 AmbientSound::draw(DrawingContext &)
00232 {
00233 }
00234 
00235 void
00236 AmbientSound::expose(HSQUIRRELVM vm, SQInteger table_idx)
00237 {
00238   scripting::AmbientSound* _this = static_cast<scripting::AmbientSound*> (this);
00239   expose_object(vm, table_idx, _this, name, false);
00240 }
00241 
00242 void
00243 AmbientSound::unexpose(HSQUIRRELVM vm, SQInteger table_idx)
00244 {
00245   scripting::unexpose_object(vm, table_idx, name);
00246 }
00247 
00248 void
00249 AmbientSound::set_pos(float x, float y)
00250 {
00251   position.x = x;
00252   position.y = y;
00253 }
00254 
00255 float
00256 AmbientSound::get_pos_x() const
00257 {
00258   return position.x;
00259 }
00260 
00261 float
00262 AmbientSound::get_pos_y() const
00263 {
00264   return position.y;
00265 }
00266 
00267 /* EOF */

Generated on Mon Apr 14 03:38:20 2014 for SuperTux by  doxygen 1.5.1