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 /++
34     Loads a Sound from a file.
35 
36     Params:
37             file =  The file where the sound is stored.
38 
39     Returns: A Sound instance loaded from the specified file.
40 +/
41 Sound loadSoundFile(in string file) @trusted {
42     version(blocksound_ALBackend) {
43         import blocksound.backend.openal : ALSound;
44 
45         return ALSound.loadSound(file);
46     } else {
47         throw new Exception("No backend avaliable! (Try compiling with version \"blocksound_ALBackend\" enabled)");
48     }
49 }
50 
51 /++
52     Loads a Sound from a file for streaming.
53 
54     Params:
55             file =  The file where the sound is stored.
56 
57     Returns: A StreamedSound instance loaded from the specified file.
58 +/
59 StreamedSound loadStreamingSoundFile(in string file, in size_t numBuffers = 4) @trusted {
60     version(blocksound_ALBackend) {
61         import blocksound.backend.openal : ALStreamedSound;
62         import derelict.openal.al : ALuint;
63 
64         return ALStreamedSound.loadSound(file, cast(ALuint) numBuffers);
65     } else {
66         throw new Exception("No backend avaliable! (Try compiling with version \"blocksound_ALBackend\" enabled)");
67     }
68 }
69 
70 /// Manages the Audio.
71 class AudioManager {
72     private Vec3 _listenerLocation;
73     private float _gain;
74 
75     private AudioBackend backend;
76     private shared ArrayList!Source sources;
77 
78     /// The location where the listener is.
79     @property Vec3 listenerLocation() @safe nothrow { return _listenerLocation; }
80     /// The location where the listener is.
81     @property void listenerLocation(Vec3 loc) @safe {
82         _listenerLocation = loc; 
83         backend.setListenerLocation(loc); 
84     }
85 
86     /// The listener's gain or volume.
87     @property float gain() @safe nothrow { return _gain; }
88     /// The listener's gain or volume.
89     @property void gain(float gain) @safe {
90         _gain = gain;
91         backend.setListenerGain(gain);
92     }
93 
94     /++
95         Initializes the AudioManager and it's backend.
96         Backend is decided at compile-time.
97     +/
98     this() @trusted {
99         import std.exception : enforce;
100         
101         enforce(INIT, new Exception("BlockSound has not been initialized!"));
102 
103         version(blocksound_ALBackend) {
104             backend = new ALAudioBackend();
105         } else {
106             throw new Exception("No backend avaliable! (Try compiling with version \"blocksound_ALBackend\" enabled)");
107         }
108 
109         sources = new ArrayList!Source();
110     }
111 
112     /++
113         Create a a new Source at the specified
114         location. The Source is also added to this AudioManager.
115 
116         Params:
117                 location =  The location of the Source.
118 
119         Returns: A new Source.
120     +/
121     Source createSource(Vec3 location) @trusted {
122         Source source = backend_createSource(location);
123         sources.add(source);
124         return source;
125     }
126 
127     /++
128         Create a a new StreamingSource at the specified
129         location. The Source is also added to this AudioManager.
130         This is for Streaming sounds.
131 
132         Params:
133                 location =  The location of the Source.
134 
135         Returns: A new Source.
136     +/
137     StreamingSource createStreamingSource(Vec3 location) @trusted {
138         StreamingSource source = backend_createStreamingSource(location);
139         sources.add(source);
140         return source;
141     }
142 
143     /++
144         Deletes a Source, frees it's resources,
145         and removes it from the AudioManager.
146 
147         Params:
148                 source =    The source to be deleted.
149     +/
150     void deleteSource(Source source) @trusted {
151         sources.remove(source);
152         source.cleanup();
153     }
154 
155     /// Cleanup any resources used by the backend.
156     void cleanup() @trusted {
157         backend.cleanup();
158     }
159 }