Browse Source

audiotraits: Add directional sound support to OpenAL (#1451)

git2323 2 years ago
parent
commit
e28697f670

+ 44 - 0
panda/src/audio/audioSound.cxx

@@ -44,6 +44,17 @@ get_3d_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz, PN_stdfloat
   // Intentionally blank.
 }
 
+void AudioSound::
+set_3d_direction(LVector3 d) {
+  // Intentionally blank.
+}
+
+LVector3 AudioSound::
+get_3d_direction() const {
+  // Intentionally blank.
+  return ( 0.0f, 0.0f, 0.0f );
+}
+
 void AudioSound::
 set_3d_min_distance(PN_stdfloat dist) {
   // Intentionally blank.
@@ -66,6 +77,39 @@ get_3d_max_distance() const {
   return 0.0f;
 }
 
+void AudioSound::
+set_3d_cone_inner_angle(PN_stdfloat angle) {
+  // Intentionally blank.
+}
+
+PN_stdfloat AudioSound::
+get_3d_cone_inner_angle() const {
+  // Intentionally blank.
+  return 0.0f;
+}
+
+void AudioSound::
+set_3d_cone_outer_angle(PN_stdfloat angle) {
+  // Intentionally blank.
+}
+
+PN_stdfloat AudioSound::
+get_3d_cone_outer_angle() const {
+  // Intentionally blank.
+  return 0.0f;
+}
+
+void AudioSound::
+set_3d_cone_outer_gain(PN_stdfloat gain) {
+  // Intentionally blank.
+}
+
+PN_stdfloat AudioSound::
+get_3d_cone_outer_gain() const {
+  // Intentionally blank.
+  return 0.0f;
+}
+
 /**
  * For use only with FMOD.
  */

+ 19 - 4
panda/src/audio/audioSound.h

@@ -19,6 +19,7 @@
 #include "typedReferenceCount.h"
 #include "pointerTo.h"
 #include "filterProperties.h"
+#include "luse.h"
 
 class AudioManager;
 
@@ -96,11 +97,12 @@ PUBLISHED:
   // Controls the position of this sound's emitter.  px, py and pz are the
   // emitter's position.  vx, vy and vz are the emitter's velocity in UNITS
   // PER SECOND (default: meters).
-  virtual void set_3d_attributes(PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz,
-                                 PN_stdfloat vx, PN_stdfloat vy, PN_stdfloat vz);
-  virtual void get_3d_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz,
-                                 PN_stdfloat *vx, PN_stdfloat *vy, PN_stdfloat *vz);
+  virtual void set_3d_attributes(PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz, PN_stdfloat vx, PN_stdfloat vy, PN_stdfloat vz);
+  virtual void get_3d_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz, PN_stdfloat *vx, PN_stdfloat *vy, PN_stdfloat *vz);
 
+  // Controls the direction of this sound emitter. Currently implemented only for OpenAL.
+  virtual void set_3d_direction(LVector3 d);
+  virtual LVector3 get_3d_direction() const;
 
   // Controls the distance (in units) that this sound begins to fall off.
   // Also affects the rate it falls off.  Default is 1.0 CloserFaster, <1.0
@@ -114,6 +116,19 @@ PUBLISHED:
   virtual void set_3d_max_distance(PN_stdfloat dist);
   virtual PN_stdfloat get_3d_max_distance() const;
 
+  // Sets the angle of the inner cone of a directional sound source. In the zone inside of the inner cone
+  // sound is emitted with the (normal) volume set by set_volume().
+  virtual void set_3d_cone_inner_angle(PN_stdfloat angle);
+  virtual PN_stdfloat get_3d_cone_inner_angle() const;
+  // Sets the angle of the outer cone of a directional sound source. In the zone between
+  // the inner and the outer cone the volume is attenuated.
+  virtual void set_3d_cone_outer_angle(PN_stdfloat angle);
+  virtual PN_stdfloat get_3d_cone_outer_angle() const;
+  // Sets a factor applied to the volume set by set_volume() for the zone outside the outer cone.
+  // By default this is 0 (so no sound is heard inside the outer zone).
+  virtual void set_3d_cone_outer_gain(PN_stdfloat gain);
+  virtual PN_stdfloat get_3d_cone_outer_gain() const;
+
   // speaker_mix is for use with FMOD.
   virtual PN_stdfloat get_speaker_mix(int speaker);
   virtual void set_speaker_mix(PN_stdfloat frontleft, PN_stdfloat frontright, PN_stdfloat center, PN_stdfloat sub, PN_stdfloat backleft, PN_stdfloat backright, PN_stdfloat sideleft, PN_stdfloat  sideright);

+ 121 - 4
panda/src/audiotraits/openalAudioSound.cxx

@@ -33,7 +33,7 @@ TypeHandle OpenALAudioSound::_type_handle;
  */
 
 OpenALAudioSound::
-OpenALAudioSound(OpenALAudioManager* manager,
+OpenALAudioSound(OpenALAudioManager *manager,
                  MovieAudio *movie,
                  bool positional,
                  int mode) :
@@ -59,7 +59,10 @@ OpenALAudioSound(OpenALAudioManager* manager,
   _current_time(0.0),
   _basename(movie->get_filename().get_basename()),
   _active(manager->get_active()),
-  _paused(false)
+  _paused(false),
+  _cone_inner_angle(360.0f),
+  _cone_outer_angle(360.0f),
+  _cone_outer_gain(0.0f)
 {
   _location[0] = 0.0f;
   _location[1] = 0.0f;
@@ -67,6 +70,9 @@ OpenALAudioSound(OpenALAudioManager* manager,
   _velocity[0] = 0.0f;
   _velocity[1] = 0.0f;
   _velocity[2] = 0.0f;
+  _direction[0] = 0.0f;
+  _direction[1] = 0.0f;
+  _direction[2] = 0.0f;
 
   ReMutexHolder holder(OpenALAudioManager::_lock);
 
@@ -122,7 +128,7 @@ play() {
 
   if (!is_valid()) return;
 
-  PN_stdfloat px,py,pz,vx,vy,vz;
+  PN_stdfloat px, py, pz, vx, vy, vz;
 
   if (!_active) {
     _paused = true;
@@ -157,8 +163,9 @@ play() {
   set_3d_min_distance(_min_dist);
   set_3d_max_distance(_max_dist);
   set_3d_drop_off_factor(_drop_off_factor);
-  get_3d_attributes(&px,&py,&pz,&vx,&vy,&vz);
+  get_3d_attributes(&px, &py, &pz, &vx, &vy, &vz);
   set_3d_attributes(px, py, pz, vx, vy, vz);
+  set_3d_direction(get_3d_direction());
 
   _playing_loops = _loop_count;
   if (_playing_loops == 0) {
@@ -762,6 +769,41 @@ get_3d_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz, PN_stdfloat
   *vz = _velocity[1];
 }
 
+/**
+* Set the direction of this sound
+*
+* Both Panda3D and OpenAL use a right handed coordinate system.  However, in
+* Panda3D the Y-Axis is going into the Screen and the Z-Axis is going up.  In
+* OpenAL the Y-Axis is going up and the Z-Axis is coming out of the screen.
+*
+* The solution is simple, we just flip the Y and Z axis and negate the Z, as
+* we move coordinates from Panda to OpenAL and back.
+*/
+void OpenALAudioSound::
+set_3d_direction(LVector3 d) {
+  ReMutexHolder holder(OpenALAudioManager::_lock);
+  _direction[0] = d.get_x();
+  _direction[1] = d.get_z();
+  _direction[2] = -d.get_y();
+
+  if (is_playing()) {
+    _manager->make_current();
+
+    alGetError(); // clear errors
+    alSourcefv(_source, AL_DIRECTION, _direction);
+    al_audio_errcheck("alSourcefv(_source,AL_DIRECTION)");
+  }
+}
+
+/**
+ * Get the direction of this sound.
+ */
+LVector3 OpenALAudioSound::
+get_3d_direction() const {
+  ReMutexHolder holder(OpenALAudioManager::_lock);
+  return LVector3(_direction[0], -_direction[2], _direction[1]);
+}
+
 /**
  * Set the distance that this sound begins to fall off.  Also affects the rate
  * it falls off.
@@ -838,6 +880,81 @@ get_3d_drop_off_factor() const {
   return _drop_off_factor;
 }
 
+/**
+ * Set the inner angle of a directional sound
+ */
+void OpenALAudioSound::
+set_3d_cone_inner_angle(PN_stdfloat angle) {
+  ReMutexHolder holder(OpenALAudioManager::_lock);
+  _cone_inner_angle = angle;
+
+  if (is_playing()) {
+    _manager->make_current();
+
+    alGetError(); // clear errors
+    alSourcef(_source, AL_CONE_INNER_ANGLE, _cone_inner_angle);
+    al_audio_errcheck("alSourcefv(_source,AL_CONE_INNER_ANGLE)");
+  }
+}
+
+/**
+ * Get the inner angle of a directional sound
+ */
+PN_stdfloat OpenALAudioSound::
+get_3d_cone_inner_angle() const {
+  return _cone_inner_angle;
+}
+
+/**
+ * Set the outer angle of a directional sound
+ */
+void OpenALAudioSound::
+set_3d_cone_outer_angle(PN_stdfloat angle) {
+  ReMutexHolder holder(OpenALAudioManager::_lock);
+  _cone_outer_angle = angle;
+
+  if (is_playing()) {
+    _manager->make_current();
+
+    alGetError(); // clear errors
+    alSourcef(_source, AL_CONE_OUTER_ANGLE, _cone_outer_angle);
+    al_audio_errcheck("alSourcefv(_source,AL_CONE_OUTER_ANGLE)");
+  }
+}
+
+/**
+ * Get the outer angle of a directional sound
+ */
+PN_stdfloat OpenALAudioSound::
+get_3d_cone_outer_angle() const {
+  return _cone_outer_angle;
+}
+
+/**
+ * Set the outer gain factor of a directional sound
+ */
+void OpenALAudioSound::
+set_3d_cone_outer_gain(PN_stdfloat gain) {
+  ReMutexHolder holder(OpenALAudioManager::_lock);
+  _cone_outer_gain = gain;
+
+  if (is_playing()) {
+    _manager->make_current();
+
+    alGetError(); // clear errors
+    alSourcef(_source, AL_CONE_OUTER_GAIN, _cone_outer_gain);
+    al_audio_errcheck("alSourcefv(_source,AL_CONE_OUTER_GAIN)");
+  }
+}
+
+/**
+ * Get the outer gain of a directional sound
+ */
+PN_stdfloat OpenALAudioSound::
+get_3d_cone_outer_gain() const {
+  return _cone_outer_gain;
+}
+
 /**
  * Sets whether the sound is marked "active".  By default, the active flag is
  * true for all sounds.  If the active flag is set to false for any particular

+ 22 - 0
panda/src/audiotraits/openalAudioSound.h

@@ -90,6 +90,10 @@ public:
   void set_3d_attributes(PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz, PN_stdfloat vx, PN_stdfloat vy, PN_stdfloat vz);
   void get_3d_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz, PN_stdfloat *vx, PN_stdfloat *vy, PN_stdfloat *vz);
 
+  // Controls the direction of this sound emitter.
+  void set_3d_direction(LVector3 d);
+  LVector3 get_3d_direction() const;
+
   void set_3d_min_distance(PN_stdfloat dist);
   PN_stdfloat get_3d_min_distance() const;
 
@@ -99,6 +103,15 @@ public:
   void set_3d_drop_off_factor(PN_stdfloat factor);
   PN_stdfloat get_3d_drop_off_factor() const;
 
+  void set_3d_cone_inner_angle(PN_stdfloat angle);
+  PN_stdfloat get_3d_cone_inner_angle() const;
+
+  void set_3d_cone_outer_angle(PN_stdfloat angle);
+  PN_stdfloat get_3d_cone_outer_angle() const;
+
+  void set_3d_cone_outer_gain(PN_stdfloat gain);
+  PN_stdfloat get_3d_cone_outer_gain() const;
+
   AudioSound::SoundStatus status() const;
 
   void finished();
@@ -154,6 +167,7 @@ private:
 
   ALfloat _location[3];
   ALfloat _velocity[3];
+  ALfloat _direction[3];
 
   PN_stdfloat _min_dist;
   PN_stdfloat _max_dist;
@@ -191,6 +205,14 @@ private:
   bool _active;
   bool _paused;
 
+  // these settings are used to define a directional sound source. The inner angle
+  // defines a cone wherein the sound can be heard with normal volume. _cone_outer_angle defines a second cone.
+  // Between the inner and the outer cone the volume is attenuated.
+  // _cone_outer_gain is a factor applied to the volume setting to define the volume in the zone outside of the outer cone.
+  PN_stdfloat _cone_inner_angle;
+  PN_stdfloat _cone_outer_angle;
+  PN_stdfloat _cone_outer_gain;
+
 public:
   static TypeHandle get_class_type() {
     return _type_handle;