private void InitBuffer(UUID soundId, bool loop, bool global, Vector3 worldpos, float vol)\r
{\r
// Do not let this get garbage-collected.\r
- allBuffers.AddLast(this);\r
+ lock (allBuffers)\r
+ allBuffers.Add(soundId,this);\r
\r
Id = soundId;\r
position = FromOMVSpace(worldpos);\r
new AssetManager.AssetReceivedCallback(Assets_OnSoundReceived));\r
}\r
\r
+ public static void Kill( UUID id )\r
+ {\r
+ if (allBuffers.ContainsKey(id))\r
+ {\r
+ BufferSound bs = allBuffers[id];\r
+ bs.StopSound();\r
+ }\r
+ }\r
+\r
public BufferSound( UUID soundId )\r
: base()\r
{\r
- allBuffers.AddLast(this);\r
+ lock (allBuffers)\r
+ allBuffers.Add(soundId,this);\r
prefetchOnly = true;\r
Id = soundId;\r
\r
// If this was a Prefetch, just stop here.\r
if (prefetchOnly)\r
{\r
- allBuffers.Remove(this);\r
+ allBuffers.Remove(Id);\r
return;\r
}\r
\r
+ Logger.Log("Opening sound " + Id.ToString(), Helpers.LogLevel.Debug);\r
+\r
// Decode the Ogg Vorbis buffer.\r
AssetSound s = asset as AssetSound;\r
s.Decode();\r
1.2f, // Any closer than this gets no louder\r
20.0f)); // Further than this gets no softer.\r
\r
- // Set the sound point of origin.\r
+ // Set the sound point of origin. This is in GLOBAL coordinates.\r
FMODExec(channel.set3DAttributes(ref position, ref ZeroVector));\r
\r
// Turn off pause mode. The sound will start playing now.\r
}\r
catch (Exception ex)\r
{\r
- Logger.Log("Error starting sound: ", Helpers.LogLevel.Debug, ex);\r
+ Logger.Log("Error starting sound: ", Helpers.LogLevel.Error, ex);\r
}\r
\r
return RESULT.OK;\r
// Ignore other callback types.\r
if (type != CHANNEL_CALLBACKTYPE.END) return RESULT.OK;\r
\r
- // Release the buffer to avoid a big memory leak.\r
+ StopSound();\r
\r
+ return RESULT.OK;\r
+ }\r
+\r
+ protected void StopSound()\r
+ {\r
+ Logger.Log("Removing sound " + Id.ToString(), Helpers.LogLevel.Debug);\r
+\r
+ // Release the buffer to avoid a big memory leak.\r
+ if (channel != null)\r
+ {\r
+ channel.stop();\r
+ channel = null;\r
+ }\r
if (sound != null)\r
{\r
sound.release();\r
}\r
channel = null;\r
\r
- allBuffers.Remove(this);\r
-\r
- return RESULT.OK;\r
+ lock (allBuffers)\r
+ allBuffers.Remove(Id);\r
}\r
\r
}\r
loadCallback = new FMOD.SOUND_NONBLOCKCALLBACK(DispatchNonBlockCallback);
endCallback = new FMOD.CHANNEL_CALLBACK(DispatchEndCallback);
- allBuffers = new LinkedList<BufferSound>();
+ allBuffers = new Dictionary<UUID,BufferSound>();
// Start the background thread that does all the FMOD calls.
soundThread = new Thread(new ThreadStart(CommandLoop));
while (true)
{
+ // Two updates per second.
Thread.Sleep(500);
if (system == null) continue;
AgentManager my = Instance.Client.Self;
+ Vector3 newPosition = new Vector3(my.GlobalPosition);
+
// If we are standing still, nothing to update now, but
// FMOD needs a 'tick' anyway for callbacks, etc. In looping
// 'game' programs, the loop is the 'tick'. Since Radegast
// uses events and has no loop, we use this position update
// thread to drive the FMOD tick.
- if (my.SimPosition.Equals(lastpos) &&
+ if (newPosition.Equals(lastpos) &&
my.Movement.BodyRotation.W == lastface)
{
invoke(new SoundDelegate(delegate
continue;
}
- lastpos = my.SimPosition;
+ // We have moved or turned. Remember new position.
+ lastpos = newPosition;
lastface = my.Movement.BodyRotation.W;
// Convert coordinate spaces.
// By definition, facing.W = Cos( angle/2 )
double angle = 2.0 * Math.Acos(my.Movement.BodyRotation.W);
FMOD.VECTOR forward = new FMOD.VECTOR();
- forward.x = (float)Math.Asin(angle);
+ forward.x = (float)Math.Sin(angle);
forward.y = 0.0f;
- forward.z = (float)Math.Acos(angle);
+ forward.z = (float)Math.Cos(angle);
+ int facing = (int)(angle * 180.0 / 3.141592);
+ Logger.Log("Facing "+facing.ToString(), Helpers.LogLevel.Debug);
// Tell FMOD the new orientation.
invoke( new SoundDelegate( delegate
}
}
- /**
- * Handle triggering a sound to play
- */
+ /// <summary>
+ /// Handle request to play a sound, which might (or mioght not) have been preloaded.
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e"></param>
private void Sound_SoundTrigger(object sender, SoundTriggerEventArgs e)
{
+ Logger.Log("Trigger sound " + e.SoundID.ToString() +
+ " in object " + e.ObjectID.ToString(),
+ Helpers.LogLevel.Debug);
+
new BufferSound(
e.SoundID,
false,
}
- /**
- * Handle request to preload a sound resource.
- */
+
+ /// <summary>
+ /// Handle request to preload a sound for playing later.
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e"></param>
private void Sound_PreloadSound(object sender, PreloadSoundEventArgs e)
{
+ Logger.Log("Prefetch sound " + e.SoundID.ToString() +
+ " in object " + e.ObjectID.ToString(),
+ Helpers.LogLevel.Debug);
+
new BufferSound( e.SoundID );
}
+ /// <summary>
+ /// Handle object updates, looking for sound events
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e"></param>
private void Objects_ObjectUpdate(object sender, PrimEventArgs e)
{
// Objects without sounds are not interesting.
if ((e.Prim.SoundFlags & SoundFlags.Stop) == SoundFlags.Stop)
{
+ BufferSound.Kill(e.Prim.Sound);
+ return;
}
+ Logger.Log("Object sound " + e.Prim.Sound.ToString() +
+ " in object " + e.Prim.ID.ToString(),
+ Helpers.LogLevel.Debug);
+
Vector3 fullPosition = e.Prim.Position;
if (e.Prim.ParentID != 0)
{
}
}
- public class PlayingSound
- {
- private UUID Id;
- private Vector3 position;
- private float volume;
-
- public PlayingSound( UUID soundId )
- {
- Id = soundId;
- }
- }
-
public class MediaException : Exception
{
public MediaException(string msg)