1 /* 2 * zlib License 3 * 4 * (C) 2016 jython234 5 * 6 * This software is provided 'as-is', without any express or implied 7 * warranty. In no event will the authors be held liable for any damages 8 * arising from the use of this software. 9 * 10 * Permission is granted to anyone to use this software for any purpose, 11 * including commercial applications, and to alter it and redistribute it 12 * freely, subject to the following restrictions: 13 * 14 * 1. The origin of this software must not be misrepresented; you must not 15 * claim that you wrote the original software. If you use this software 16 * in a product, an acknowledgment in the product documentation would be 17 * appreciated but is not required. 18 * 2. Altered source versions must be plainly marked as such, and must not be 19 * misrepresented as being the original software. 20 * 3. This notice may not be removed or altered from any source distribution. 21 */ 22 module blocksound.audio; 23 24 import blocksound.core; 25 import blocksound.backend.types; 26 27 public import blocksound.backend.types : Source, Sound, StreamingSource, StreamedSound; 28 29 version(blocksound_ALBackend) { 30 import blocksound.backend.openal; 31 } 32 33 class Lock { 34 35 } 36 37 /++ 38 Loads a Sound from a file. 39 40 Params: 41 file = The file where the sound is stored. 42 43 Returns: A Sound instance loaded from the specified file. 44 +/ 45 Sound loadSoundFile(in string file) @trusted { 46 version(blocksound_ALBackend) { 47 import blocksound.backend.openal : ALSound; 48 49 return ALSound.loadSound(file); 50 } else { 51 throw new Exception("No backend avaliable! (Try compiling with version \"blocksound_ALBackend\" enabled)"); 52 } 53 } 54 55 /++ 56 Loads a Sound from a file for streaming. 57 58 Params: 59 file = The file where the sound is stored. 60 61 Returns: A StreamedSound instance loaded from the specified file. 62 +/ 63 StreamedSound loadStreamingSoundFile(in string file, in size_t numBuffers = 4) @trusted { 64 version(blocksound_ALBackend) { 65 import blocksound.backend.openal : ALStreamedSound; 66 import derelict.openal.al : ALuint; 67 68 return ALStreamedSound.loadSound(file, cast(ALuint) numBuffers); 69 } else { 70 throw new Exception("No backend avaliable! (Try compiling with version \"blocksound_ALBackend\" enabled)"); 71 } 72 } 73 74 /// Manages the Audio. 75 class AudioManager { 76 private shared Lock listenerLock; 77 private shared Lock gainLock; 78 79 private shared Vec3 _listenerLocation; 80 private shared float _gain; 81 82 private AudioBackend backend; 83 private shared ArrayList!Source sources; 84 85 /// The location where the listener is. 86 @property Vec3 listenerLocation() @trusted { 87 synchronized(listenerLock) { 88 return cast(Vec3) _listenerLocation; 89 } 90 } 91 /// The location where the listener is. 92 @property void listenerLocation(Vec3 loc) @safe { 93 synchronized(listenerLock) { 94 _listenerLocation = cast(shared) loc; 95 backend.setListenerLocation(loc); 96 } 97 } 98 99 /// The listener's gain or volume. 100 @property float gain() @trusted { 101 synchronized(gainLock) { 102 return cast(shared) _gain; 103 } 104 } 105 /// The listener's gain or volume. 106 @property void gain(float gain) @safe { 107 synchronized(gainLock) { 108 _gain = cast(shared) gain; 109 backend.setListenerGain(gain); 110 } 111 } 112 113 /++ 114 Initializes the AudioManager and it's backend. 115 Backend is decided at compile-time. 116 +/ 117 this() @trusted { 118 import std.exception : enforce; 119 120 enforce(INIT, new Exception("BlockSound has not been initialized!")); 121 122 version(blocksound_ALBackend) { 123 backend = new ALAudioBackend(); 124 } else { 125 throw new Exception("No backend avaliable! (Try compiling with version \"blocksound_ALBackend\" enabled)"); 126 } 127 128 listenerLock = cast(shared) new Lock(); 129 gainLock = cast(shared) new Lock(); 130 131 sources = new ArrayList!Source(); 132 } 133 134 /++ 135 Create a a new Source at the specified 136 location. The Source is also added to this AudioManager. 137 138 Params: 139 location = The location of the Source. 140 141 Returns: A new Source. 142 +/ 143 Source createSource(Vec3 location) @trusted { 144 Source source = backend_createSource(location); 145 sources.add(source); 146 return source; 147 } 148 149 /++ 150 Create a a new StreamingSource at the specified 151 location. The Source is also added to this AudioManager. 152 This is for Streaming sounds. 153 154 Params: 155 location = The location of the Source. 156 157 Returns: A new Source. 158 +/ 159 StreamingSource createStreamingSource(Vec3 location) @trusted { 160 StreamingSource source = backend_createStreamingSource(location); 161 sources.add(source); 162 return source; 163 } 164 165 /++ 166 Deletes a Source, frees it's resources, 167 and removes it from the AudioManager. 168 169 Params: 170 source = The source to be deleted. 171 +/ 172 void deleteSource(Source source) @trusted { 173 sources.remove(source); 174 source.cleanup(); 175 } 176 177 /// Cleanup any resources used by the backend. 178 void cleanup() @trusted { 179 backend.cleanup(); 180 } 181 }