Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
AudioListenerProcessor.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 
4 using System.Linq;
5 using System.Collections.Generic;
6 using System.Collections.Specialized;
7 
8 using SiliconStudio.Core;
9 using SiliconStudio.Core.Collections;
10 using SiliconStudio.Core.Mathematics;
11 
12 using SiliconStudio.Paradox.EntityModel;
13 using SiliconStudio.Paradox.Audio;
14 using SiliconStudio.Paradox.Games;
15 
16 namespace SiliconStudio.Paradox.Engine
17 {
18  /// <summary>
19  /// Processor in charge of creating and updating the <see cref="AudioListener"/> data associated to the scene <see cref="AudioListenerComponent"/>s.
20  /// </summary>
21  /// <remarks>
22  /// The processor updates only <see cref="AudioListener"/> associated to <see cref="AudioListenerComponent"/>s
23  /// added to the <see cref="AudioSystem"/> via the <see cref="AudioSystem.AddListener"/> function.
24  /// The processor is subscribing to the <see cref="audioSystem"/> <see cref="AudioListenerComponent"/> collection events to be informed of required <see cref="AudioEmitter"/> updates.
25  /// When a <see cref="AudioListenerComponent"/> is added to the <see cref="audioSystem"/>, the processor set the associated <see cref="AudioEmitter"/>.
26  /// When a <see cref="AudioListenerComponent"/> is removed from the entity system,
27  /// the processor set the <see cref="AudioEmitter"/> reference of the <see cref="AudioSystem"/> to null
28  /// but do not remove the <see cref="AudioListenerComponent"/> from its collection.
29  /// </remarks>
30  public class AudioListenerProcessor : EntityProcessor<AudioListenerProcessor.AssociatedData>
31  {
32  /// <summary>
33  /// Reference to the <see cref="AudioSystem"/> of the game instance.
34  /// </summary>
35  private AudioSystem audioSystem;
36 
37  // expose internal member to allow debug (use directly matchingEntities if not for debug uses)
38  internal Dictionary<Entity, AssociatedData> MatchingEntitiesForDebug { get { return matchingEntities; } }
39 
40  /// <summary>
41  /// Create a new instance of AudioListenerProcessor.
42  /// </summary>
44  : base(new PropertyKey[] { AudioListenerComponent.Key, TransformationComponent.Key })
45  {
46  }
47 
48  protected override AssociatedData GenerateAssociatedData(Entity entity)
49  {
50  // Initialize TransformationComponent and ListenerComponent fields of the matchingEntities' AssociatedData.
51  // other fields are initialized in OnEntityAdded or OnListenerCollectionChanged
52  return new AssociatedData { TransformationComponent = entity.Get(TransformationComponent.Key),
53  ListenerComponent = entity.Get(AudioListenerComponent.Key) };
54  }
55 
56  protected internal override void OnSystemAdd()
57  {
58  base.OnSystemAdd();
59 
60  audioSystem = Services.GetServiceAs<AudioSystem>();
61 
62  audioSystem.Listeners.CollectionChanged += OnListenerCollectionChanged;
63  }
64 
65  protected internal override void OnSystemRemove()
66  {
67  base.OnSystemRemove();
68 
69  audioSystem.Listeners.CollectionChanged -= OnListenerCollectionChanged;
70 
71  // ensure that all associated AudioEmitter of the AudioSystem are put to null since not updated anymore.
72  foreach (var audioListenerComp in audioSystem.Listeners.Keys)
73  audioSystem.Listeners[audioListenerComp] = null;
74  }
75 
76  protected override void OnEntityAdding(Entity entity, AssociatedData data)
77  {
78  base.OnEntityAdding(entity, data);
79 
80  // initialize the AudioEmitter and mark it for update if it is present in the AudioSystem collection.
81  if (audioSystem.Listeners.ContainsKey(data.ListenerComponent))
82  {
83  InitializeAudioEmitter(data);
84  data.ShouldBeComputed = true;
85  }
86  }
87 
88  private void InitializeAudioEmitter(AssociatedData data)
89  {
90  // initialize emitter position
91  data.TransformationComponent.UpdateWorldMatrix(); // ensure that value of the worldMatrix is correct
92  data.AudioListener = new AudioListener { Position = data.TransformationComponent.WorldMatrix.TranslationVector }; // we need a valid value of Position for the first Update (Velocity computation).
93 
94  if (!audioSystem.Listeners.ContainsKey(data.ListenerComponent))
95  throw new AudioEngineInternalExceptions("Initialized AudioListenerComponent was not in AudioSystem.ListenerList");
96 
97  // set reference to the AudioEmitter of AudioSytem.
98  audioSystem.Listeners[data.ListenerComponent] = data.AudioListener;
99  }
100 
101  protected override void OnEntityRemoved(Entity entity, AssociatedData data)
102  {
103  base.OnEntityRemoved(entity, data);
104 
105  // set the reference to the AudioEmitter of AudioSystem to null since not valid anymore.
106  if (audioSystem.Listeners.ContainsKey(data.ListenerComponent))
107  {
108  audioSystem.Listeners[data.ListenerComponent] = null;
109  }
110  }
111 
112  public override void Draw(GameTime time)
113  {
114  base.Draw(time);
115 
116  foreach (var listenerData in matchingEntities.Values)
117  {
118  if(!listenerData.ShouldBeComputed) // skip all updates if the listener is not used.
119  continue;
120 
121  var worldMatrix = listenerData.TransformationComponent.WorldMatrix;
122  var listener = listenerData.AudioListener;
123  var newPosition = worldMatrix.TranslationVector;
124 
125  listener.Velocity = newPosition - listener.Position; // estimate velocity from last and new position
126  listener.Position = newPosition;
127  listener.Forward = Vector3.Normalize((Vector3)worldMatrix.Row3);
128  listener.Up = Vector3.Normalize((Vector3)worldMatrix.Row2);
129  }
130  }
131 
132  /// <summary>
133  /// The <see cref="AudioSystem"/> listeners collection has been modified.
134  /// Mark AudioEmitter not for update if removed from the list.
135  /// Create the AudioEmitter data and mark it for update if added to the list.
136  /// </summary>
137  /// <param name="o"></param>
138  /// <param name="args"></param>
139  private void OnListenerCollectionChanged(object o, TrackingCollectionChangedEventArgs args)
140  {
141  if (!args.CollectionChanged) // no keys have been added or removed, only one of the values changed
142  return;
143 
144  var listenersData = matchingEntities.Values.Where(x => x.ListenerComponent == args.Key);
145 
146  if (args.Action == NotifyCollectionChangedAction.Add) // A new listener have been added
147  {
148  foreach (var listenerData in listenersData)
149  {
150  InitializeAudioEmitter(listenerData);
151  listenerData.ShouldBeComputed = true;
152  }
153  }
154  else if(args.Action == NotifyCollectionChangedAction.Remove) // A listener have been removed
155  {
156  foreach (var listenerData in listenersData)
157  listenerData.ShouldBeComputed = false;
158  }
159  }
160 
161  public class AssociatedData
162  {
163  /// <summary>
164  /// Boolean indicating whether the AudioEmitter need to be updated for the current loop turn or not.
165  /// </summary>
166  public bool ShouldBeComputed;
167 
168  /// <summary>
169  /// The <see cref="Audio.AudioListener"/> associated to the below <see cref="AudioListenerComponent"/>.
170  /// </summary>
172 
173  /// <summary>
174  /// The <see cref="AudioListenerComponent"/> associated to the entity.
175  /// </summary>
177 
178  /// <summary>
179  /// The <see cref="TransformationComponent"/> associated to the entity.
180  /// </summary>
182  }
183  }
184 }
Represents a 3D audio listener in the audio scene. This object, used in combination with an AudioEmit...
override void OnEntityAdding(Entity entity, AssociatedData data)
AudioListenerComponent ListenerComponent
The AudioListenerComponent associated to the entity.
Game entity. It usually aggregates multiple EntityComponent
Definition: Entity.cs:28
bool ShouldBeComputed
Boolean indicating whether the AudioEmitter need to be updated for the current loop turn or not...
AudioListener AudioListener
The Audio.AudioListener associated to the below AudioListenerComponent.
override AssociatedData GenerateAssociatedData(Entity entity)
Defines Position, Rotation and Scale of its Entity.
Component representing an audio listener.
AudioListenerProcessor()
Create a new instance of AudioListenerProcessor.
override void OnEntityRemoved(Entity entity, AssociatedData data)
Entity processor, triggered on various EntitySystem events such as Entity and Component additions and...
TransformationComponent TransformationComponent
The TransformationComponent associated to the entity.
Current timing used for variable-step (real time) or fixed-step (game time) games.
Definition: GameTime.cs:31
static PropertyKey< AudioListenerComponent > Key
NotifyCollectionChangedAction Action
Gets the type of action performed. Allowed values are NotifyCollectionChangedAction.Add and NotifyCollectionChangedAction.Remove.
bool CollectionChanged
Gets a value indicating whether [collection changed (not a replacement but real insertion/removal)].
SiliconStudio.Core.Mathematics.Vector3 Vector3
The Audio System. It creates an underlying instance of AudioEngine.
Definition: AudioSystem.cs:16
A class that represents a tag propety.
Definition: PropertyKey.cs:17
Processor in charge of creating and updating the AudioListener data associated to the scene AudioList...