1 module polyplex.core.audio; 2 import polyplex.utils.logging; 3 import openal; 4 public import polyplex.core.audio.soundeffect; 5 public import polyplex.core.audio.music; 6 public import polyplex.core.audio.syncgroup; 7 public import polyplex.core.audio.effect; 8 9 public enum AudioRenderFormats : int { 10 /** 11 Auto detect (only available for PPC Audio streams) 12 */ 13 Auto = 0, 14 Mono8 = AL_FORMAT_MONO8, 15 Mono16 = AL_FORMAT_MONO16, 16 MonoFloat = AL_FORMAT_MONO_FLOAT32, 17 18 Stereo8 = AL_FORMAT_STEREO8, 19 Stereo16 = AL_FORMAT_STEREO16, 20 StereoFloat = AL_FORMAT_STEREO_FLOAT32, 21 } 22 23 public enum ALExtensionSupport { 24 /** 25 Basic OpenAL context is supported. 26 */ 27 Basic = 0x00, 28 29 /** 30 EAX 2.0 is supported. 31 */ 32 EAX2 = 0x01, 33 34 /** 35 EFX is supported. 36 */ 37 EFX = 0x02, 38 39 /** 40 OpenAL-Soft effect chaining 41 */ 42 EffectChaining = 0x04 43 // TODO add more extensions here. 44 } 45 46 public static AudioDevice DefaultAudioDevice; 47 48 //TODO: remove this 49 enum ErrCodes : ALCenum { 50 ALC_FREQUENCY = 0x1007, 51 ALC_REFRESH = 0x1008, 52 ALC_SYNC = 0x1009, 53 54 ALC_MONO_SOURCES = 0x1010, 55 ALC_STEREO_SOURCES = 0x1011, 56 57 ALC_NO_ERROR = ALC_FALSE, 58 ALC_INVALID_DEVICE = 0xA001, 59 ALC_INVALID_CONTEXT = 0xA002, 60 ALC_INVALID_ENUM = 0xA003, 61 ALC_INVALID_VALUE = 0xA004, 62 ALC_OUT_OF_MEMORY = 0xA005, 63 64 ALC_DEFAULT_DEVICE_SPECIFIER = 0x1004, 65 ALC_DEVICE_SPECIFIER = 0x1005, 66 ALC_EXTENSIONS = 0x1006, 67 68 ALC_MAJOR_VERSION = 0x1000, 69 ALC_MINOR_VERSION = 0x1001, 70 71 ALC_ATTRIBUTES_SIZE = 0x1002, 72 ALC_ALL_ATTRIBUTES = 0x1003, 73 74 ALC_CAPTURE_DEVICE_SPECIFIER = 0x310, 75 ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER = 0x311, 76 ALC_CAPTURE_SAMPLES = 0x312, 77 } 78 79 protected __gshared ALint maxSlots; 80 81 public class AudioDevice { 82 private static bool deviceCreationSucceeded; 83 public ALCdevice* ALDevice; 84 public ALCcontext* ALContext; 85 private static ALExtensionSupport supportedExtensions; 86 public static ALint MixerSize = 10; 87 88 public static bool DeviceCreationSucceeded() { 89 return deviceCreationSucceeded; 90 } 91 92 public static ALExtensionSupport SupportedExtensions() { 93 return supportedExtensions; 94 } 95 96 /** 97 Constucts an audio device, NULL for preffered device. 98 */ 99 this(string device = null) { 100 ALint[] attribs = null; 101 102 Logger.Info("Initializing OpenAL device..."); 103 ALCdevice* dev = alcOpenDevice(device.ptr); 104 105 // If EAX 2.0 is supported, flag it as supported. 106 bool supex = cast(bool)alIsExtensionPresent("EAX2.0"); 107 if (supex) { 108 Logger.Success("EAX 2.0 extensions are supported!"); 109 supportedExtensions |= ALExtensionSupport.EAX2; 110 } 111 112 // If EFX is supported, flag it as supported. 113 supex = cast(bool)alcIsExtensionPresent(dev, "ALC_EXT_EFX"); 114 if (supex) { 115 supportedExtensions |= ALExtensionSupport.EFX; 116 Logger.Success("EFX extensions are supported!"); 117 Logger.Info("Setting up mixer channel count..."); 118 attribs = new ALint[4]; 119 attribs[0] = ALC_MAX_AUXILIARY_SENDS; 120 attribs[1] = MixerSize; 121 } 122 123 // If Effect Chaining is supported, flag it as supported. 124 supex = cast(bool)alcIsExtensionPresent(dev, "AL_SOFTX_effect_chain"); 125 if (supex) { 126 supportedExtensions |= ALExtensionSupport.EffectChaining; 127 Logger.Success("Effect chains are supported!"); 128 } 129 130 if (dev) { 131 ALContext = alcCreateContext(dev, attribs.ptr); 132 alcMakeContextCurrent(ALContext); 133 } else { 134 import std.conv; 135 import std.stdio; 136 Logger.Err("Could not create device! {0}", (cast(ErrCodes)alcGetError(dev)).to!string); 137 deviceCreationSucceeded = false; 138 return; 139 } 140 if (supex) { 141 ALint sourceMax; 142 alcGetIntegerv(dev, ALC_MAX_AUXILIARY_SENDS, 1, &sourceMax); 143 144 maxSlots = sourceMax; 145 146 Logger.Info("Created {0} mixer sends", sourceMax); 147 } 148 deviceCreationSucceeded = true; 149 } 150 151 ~this() { 152 alcMakeContextCurrent(null); 153 alcDestroyContext(ALContext); 154 alcCloseDevice(ALDevice); 155 } 156 157 /** 158 Makes the context for this device, a current context. 159 */ 160 public void MakeCurrent() { 161 alcMakeContextCurrent(ALContext); 162 } 163 }