public OpenALDevice() { string envDevice = Environment.GetEnvironmentVariable("FNA_AUDIO_DEVICE_NAME"); if (String.IsNullOrEmpty(envDevice)) { /* Be sure ALC won't explode if the variable doesn't exist. * But, fail if the device name is wrong. The user needs to know * if their environment variable was incorrect. * -flibit */ envDevice = String.Empty; } alDevice = ALC10.alcOpenDevice(envDevice); if (CheckALCError() || alDevice == IntPtr.Zero) { throw new InvalidOperationException("Could not open audio device!"); } int[] attribute = new int[0]; alContext = ALC10.alcCreateContext(alDevice, attribute); if (CheckALCError() || alContext == IntPtr.Zero) { Dispose(); throw new InvalidOperationException("Could not create OpenAL context"); } ALC10.alcMakeContextCurrent(alContext); if (CheckALCError()) { Dispose(); throw new InvalidOperationException("Could not make OpenAL context current"); } float[] ori = new float[] { 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f }; AL10.alListenerfv(AL10.AL_ORIENTATION, ori); AL10.alListener3f(AL10.AL_POSITION, 0.0f, 0.0f, 0.0f); AL10.alListener3f(AL10.AL_VELOCITY, 0.0f, 0.0f, 0.0f); AL10.alListenerf(AL10.AL_GAIN, 1.0f); EFX.alGenFilters(1, out INTERNAL_alFilter); // FIXME: Remove for FNA 16.11! -flibit if (!AL10.alIsExtensionPresent("AL_SOFT_gain_clamp_ex")) { FNALoggerEXT.LogWarn("AL_SOFT_gain_clamp_ex not found!"); FNALoggerEXT.LogWarn("Update your OpenAL Soft library!"); } }
public static void Create() { IntPtr ctx; try { FAudio.FAudioCreate( out ctx, 0, FAudio.FAUDIO_DEFAULT_PROCESSOR ); } catch (Exception e) { /* FAudio is missing, bail! */ FNALoggerEXT.LogWarn("FAudio failed to load: " + e.ToString()); return; } uint devices; FAudio.FAudio_GetDeviceCount( ctx, out devices ); if (devices == 0) { /* No sound cards, bail! */ FAudio.FAudio_Release(ctx); return; } FAudioContext context = new FAudioContext(ctx, devices); if (context.Handle == IntPtr.Zero) { /* Soundcard failed to configure, bail! */ context.Dispose(); return; } Context = context; }
public static void Initialize() { // We should only have one of these! if (ALDevice != null) { FNALoggerEXT.LogWarn("ALDevice already exists, overwriting!"); } bool disableSound = Environment.GetEnvironmentVariable( "FNA_AUDIO_DISABLE_SOUND" ) == "1"; if (disableSound) { ALDevice = new NullALDevice(); } else { ALDevice = FNAPlatform.CreateALDevice(); } // Populate device info if (ALDevice != null) { ALDevice.SetMasterVolume(MasterVolume); ALDevice.SetDopplerScale(DopplerScale); ALDevice.SetSpeedOfSound(SpeedOfSound); Renderers = ALDevice.GetDevices(); Microphone.All = ALDevice.GetCaptureDevices(); InstancePool = new List <SoundEffectInstance>(); DynamicInstancePool = new List <DynamicSoundEffectInstance>(); ActiveMics = new List <Microphone>(); AppDomain.CurrentDomain.ProcessExit += Dispose; } else { Renderers = new ReadOnlyCollection <RendererDetail>(new List <RendererDetail>()); Microphone.All = new ReadOnlyCollection <Microphone>(new List <Microphone>()); } }
protected T ReadAsset <T>(string assetName, Action <IDisposable> recordDisposableObject) { if (string.IsNullOrEmpty(assetName)) { throw new ArgumentNullException("assetName"); } if (disposed) { throw new ObjectDisposedException("ContentManager"); } object result = null; Stream stream = null; string modifiedAssetName = String.Empty; // Will be used if we have to guess a filename try { stream = OpenStream(assetName); } catch (Exception e) { // Okay, so we couldn't open it. Maybe it needs a different extension? // FIXME: This only works for files on the disk, what about custom streams? -flibit modifiedAssetName = MonoGame.Utilities.FileHelpers.NormalizeFilePathSeparators( Path.Combine(RootDirectoryFullPath, assetName) ); if (typeof(T) == typeof(Texture2D) || typeof(T) == typeof(Texture)) { modifiedAssetName = Texture2DReader.Normalize(modifiedAssetName); } else if ((typeof(T) == typeof(SoundEffect))) { modifiedAssetName = SoundEffectReader.Normalize(modifiedAssetName); } else if ((typeof(T) == typeof(Effect))) { modifiedAssetName = EffectReader.Normalize(modifiedAssetName); } else if ((typeof(T) == typeof(Song))) { modifiedAssetName = SongReader.Normalize(modifiedAssetName); } else if ((typeof(T) == typeof(Video))) { modifiedAssetName = VideoReader.Normalize(modifiedAssetName); } else { // No raw format available, disregard! modifiedAssetName = null; } // Did we get anything...? if (String.IsNullOrEmpty(modifiedAssetName)) { // Nope, nothing we're aware of! throw new ContentLoadException( "Could not load asset " + assetName + "! Error: " + e.Message, e ); } stream = TitleContainer.OpenStream(modifiedAssetName); } // Check for XNB header stream.Read(xnbHeader, 0, xnbHeader.Length); if (xnbHeader[0] == 'X' && xnbHeader[1] == 'N' && xnbHeader[2] == 'B' && targetPlatformIdentifiers.Contains((char)xnbHeader[3])) { using (BinaryReader xnbReader = new BinaryReader(stream)) using (ContentReader reader = GetContentReaderFromXnb(assetName, ref stream, xnbReader, (char)xnbHeader[3], recordDisposableObject)) { result = reader.ReadAsset <T>(); GraphicsResource resource = result as GraphicsResource; if (resource != null) { resource.Name = assetName; } } } else { // It's not an XNB file. Try to load as a raw asset instead. // FIXME: Assuming seekable streams! -flibit stream.Seek(0, SeekOrigin.Begin); if (typeof(T) == typeof(Texture2D) || typeof(T) == typeof(Texture)) { Texture2D texture; if (xnbHeader[0] == 'D' && xnbHeader[1] == 'D' && xnbHeader[2] == 'S' && xnbHeader[3] == ' ') { texture = Texture2D.DDSFromStreamEXT( GetGraphicsDevice(), stream ); } else { texture = Texture2D.FromStream( GetGraphicsDevice(), stream ); } texture.Name = assetName; result = texture; } else if ((typeof(T) == typeof(SoundEffect))) { result = SoundEffect.FromStream(stream); } else if ((typeof(T) == typeof(Effect))) { byte[] data = new byte[stream.Length]; stream.Read(data, 0, (int)stream.Length); result = new Effect(GetGraphicsDevice(), data); } else if ((typeof(T) == typeof(Song))) { // FIXME: Not using the stream! -flibit result = new Song(modifiedAssetName); } else if ((typeof(T) == typeof(Video))) { // FIXME: Not using the stream! -flibit result = new Video(modifiedAssetName, GetGraphicsDevice()); FNALoggerEXT.LogWarn( "Video " + modifiedAssetName + " does not have an XNB file! Hacking Duration property!" ); } else { stream.Close(); throw new ContentLoadException("Could not load " + assetName + " asset!"); } /* Because Raw Assets skip the ContentReader step, they need to have their * disposables recorded here. Doing it outside of this catch will * result in disposables being logged twice. */ IDisposable disposableResult = result as IDisposable; if (disposableResult != null) { if (recordDisposableObject != null) { recordDisposableObject(disposableResult); } else { disposableAssets.Add(disposableResult); } } /* Because we're not using a BinaryReader for raw assets, we * need to close the stream ourselves. * -flibit */ stream.Close(); } return((T)result); }
internal void Play(bool isManaged) { // No-op if we're already playing. if (State != SoundState.Stopped) { if (State == SoundState.Paused) { // ... but be sure pause/resume still works Resume(); } return; } if (INTERNAL_alSource != null) { // The sound has stopped, but hasn't cleaned up yet... AudioDevice.ALDevice.StopAndDisposeSource(INTERNAL_alSource); INTERNAL_alSource = null; } while (queuedBuffers.Count > 0) { availableBuffers.Enqueue(queuedBuffers.Dequeue()); PendingBufferCount -= 1; } if (AudioDevice.ALDevice == null) { throw new NoAudioHardwareException(); } INTERNAL_alSource = AudioDevice.ALDevice.GenSource(); if (INTERNAL_alSource == null) { FNALoggerEXT.LogWarn("AL SOURCE WAS NOT AVAILABLE, SKIPPING."); return; } // Queue the buffers to this source while (buffersToQueue.Count > 0) { IALBuffer nextBuf = buffersToQueue.Dequeue(); queuedBuffers.Enqueue(nextBuf); AudioDevice.ALDevice.QueueSourceBuffer(INTERNAL_alSource, nextBuf); } // Apply Pan/Position if (INTERNAL_positionalAudio) { INTERNAL_positionalAudio = false; AudioDevice.ALDevice.SetSourcePosition( INTERNAL_alSource, position ); } else { Pan = Pan; } // Reassign Properties, in case the AL properties need to be applied. Volume = Volume; Pitch = Pitch; // ... but wait! What if we need moar buffers? for ( int i = MINIMUM_BUFFER_CHECK - PendingBufferCount; (i > 0) && BufferNeeded != null; i -= 1 ) { BufferNeeded(this, null); } // Finally. AudioDevice.ALDevice.PlaySource(INTERNAL_alSource); if (isManaged) { AudioDevice.DynamicInstancePool.Add(this); } }
public virtual void Play() { if (State != SoundState.Stopped) { return; } if (INTERNAL_alSource != null) { // The sound has stopped, but hasn't cleaned up yet... AudioDevice.ALDevice.StopAndDisposeSource(INTERNAL_alSource); INTERNAL_alSource = null; } IALBuffer srcBuf; if (INTERNAL_positionalAudio && INTERNAL_parentEffect.INTERNAL_monoBuffer != null) { srcBuf = INTERNAL_parentEffect.INTERNAL_monoBuffer; } else { srcBuf = INTERNAL_parentEffect.INTERNAL_buffer; } INTERNAL_alSource = AudioDevice.ALDevice.GenSource( srcBuf, INTERNAL_isXACTSource ); if (INTERNAL_alSource == null) { FNALoggerEXT.LogWarn("AL SOURCE WAS NOT AVAILABLE, SKIPPING."); return; } // Apply Pan/Position if (INTERNAL_positionalAudio) { AudioDevice.ALDevice.SetSourcePosition( INTERNAL_alSource, position ); } else { Pan = Pan; } // Reassign Properties, in case the AL properties need to be applied. Volume = Volume; IsLooped = IsLooped; Pitch = Pitch; // Apply EFX if (INTERNAL_alReverb != null) { AudioDevice.ALDevice.SetSourceReverb( INTERNAL_alSource, INTERNAL_alReverb ); } AudioDevice.ALDevice.PlaySource(INTERNAL_alSource); }