2 // Radegast Metaverse Client
3 // Copyright (c) 2009, Radegast Development Team
4 // All rights reserved.
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
9 // * Redistributions of source code must retain the above copyright notice,
10 // this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 // * Neither the name of the application "Radegast", nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 using System.Collections.Generic;
34 using System.Threading;
37 namespace Radegast.Media
39 public abstract class MediaObject : Object, IDisposable
42 /// Indicates if this object's resources have already been disposed
44 public bool Disposed { get { return disposed; } }
45 private bool disposed = false;
47 /// All commands are made through queued delegate calls, so they
48 /// are guaranteed to take place in the same thread. FMOD requires this.
49 public delegate void SoundDelegate();
51 /// Queue of sound commands
54 protected static Queue<SoundDelegate> queue;
57 /// FMOD channel controller, should not be used directly, add methods to Radegast.Media.Sound
59 public Channel FMODChannel { get { return channel; } }
60 protected Channel channel = null;
62 protected FMOD.CREATESOUNDEXINFO extraInfo;
65 /// FMOD sound object, should not be used directly, add methods to Radegast.Media.Sound
67 public FMOD.Sound FMODSound { get { return sound; } }
68 protected FMOD.Sound sound = null;
70 protected static FMOD.VECTOR UpVector;
71 protected static FMOD.VECTOR ZeroVector;
73 public FMOD.System FMODSystem { get { return system; } }
75 /// Base FMOD system object, of which there is only one.
77 protected static FMOD.System system = null;
81 extraInfo = new FMOD.CREATESOUNDEXINFO();
82 extraInfo.cbsize = 10;
86 protected bool Cloned = false;
87 public virtual void Dispose()
89 if (!Cloned && sound != null)
98 public bool Active { get { return (sound != null); } }
101 /// Put a delegate call on the command queue.
103 /// <param name="action"></param>
104 protected void invoke(SoundDelegate action)
106 // Do nothing if queue not ready yet.
107 if (queue == null) return;
109 // Put that on the queue and wake up the background thread.
112 queue.Enqueue( action );
113 Monitor.Pulse(queue);
119 /// Common actgions for all sound types.
121 protected float volume = 0.5f;
130 invoke(new SoundDelegate(delegate
132 MediaManager.FMODExec(channel.setVolume(value));
142 invoke(new SoundDelegate(delegate
144 MediaManager.FMODExec(channel.stop());
150 /// Convert OpenMetaVerse to FMOD coordinate space.
152 /// <param name="omvV"></param>
153 /// <returns></returns>
154 protected FMOD.VECTOR FromOMVSpace(OpenMetaverse.Vector3 omvV)
156 // OMV X is forward, Y is left, Z is up.
157 // FMOD Z is forward, X is right, Y is up.
158 FMOD.VECTOR v = new FMOD.VECTOR();
165 protected static Dictionary<IntPtr,MediaObject> allSounds;
166 protected static Dictionary<IntPtr, MediaObject> allChannels;
167 protected void RegisterSound(FMOD.Sound sound)
169 allSounds.Add(sound.getRaw(), this);
171 protected void RegisterChannel(FMOD.Channel channel)
173 allSounds.Add(channel.getRaw(), this);
175 protected void UnRegisterSound()
177 if (sound == null) return;
178 IntPtr raw = sound.getRaw();
179 if (allSounds.ContainsKey( raw ))
181 allSounds.Remove( raw );
184 protected void UnRegisterChannel()
186 if (channel == null) return;
187 IntPtr raw = channel.getRaw();
188 if (allChannels.ContainsKey(raw))
190 allChannels.Remove(raw);
195 /// A callback for asynchronous FMOD calls.
197 /// <returns></returns>
198 protected virtual FMOD.RESULT NonBlockCallbackHandler( RESULT result ) { return RESULT.OK; }
199 protected virtual FMOD.RESULT EndCallbackHandler() { return RESULT.OK; }
201 protected RESULT DispatchNonBlockCallback(IntPtr soundraw, RESULT result)
203 if (allSounds.ContainsKey(soundraw))
205 MediaObject sndobj = allSounds[soundraw];
206 return sndobj.NonBlockCallbackHandler( result );
209 return FMOD.RESULT.OK;
212 protected RESULT DispatchEndCallback(
214 CHANNEL_CALLBACKTYPE type,
218 // Ignore other callback types.
219 if (type != CHANNEL_CALLBACKTYPE.END) return RESULT.OK;
221 if (allChannels.ContainsKey(channelraw))
223 MediaObject sndobj = allSounds[channelraw];
224 return sndobj.EndCallbackHandler();
230 public delegate RESULT SOUND_NONBLOCKCALLBACK(IntPtr soundraw, RESULT result);
232 protected static void FMODExec(FMOD.RESULT result)
234 if (result != FMOD.RESULT.OK)
236 throw new MediaException("FMOD error! " + result + " - " + FMOD.Error.String(result));