1 module fmod.fmod;
2 
3 public import derelict.fmod.fmod;
4 
5 // Wraps SoftwareFormat calls
6 struct SoftwareFormat {
7   int samplerate;
8   int numrawspeakers;
9   FMOD_SPEAKERMODE speakermode;
10 }
11 
12 struct SpeakerPosition {
13   FMOD_SPEAKER speaker;
14   float x, y;
15   bool active;
16 }
17 
18 struct StreamBufferSize {
19   uint filebuffersize, filebuffersizetype;
20 }
21 
22 struct Settings3D {
23   float dopplerscale, distancefactor, rolloffscale;
24 }
25 
26 struct SoundDefaults {
27   float  frequency;
28   int    priority;
29 }
30 
31 struct Sound3DDistance {
32   float min, max;
33 }
34 
35 struct Sound3DConeSettings {
36   float insideangle, outsideangle, outsidevolume;
37 }
38 
39 struct SoundFormat {
40   FMOD_SOUND_TYPE *type;
41   FMOD_SOUND_FORMAT *format;
42   int channels, bits;
43 }
44 
45 struct ReverbProperties {
46   int    instance;
47   float  wet;
48 }
49 
50 class FMODException : Exception {
51   FMOD_RESULT result;
52 
53   this(FMOD_RESULT result, string msg = null, Throwable next = null) {
54     this.result = result;
55     super(msg, next);
56   }
57 
58   this(FMOD_RESULT result, string msg, string file, size_t line, Throwable next = null) {
59     this.result = result;
60     super(msg, file, line, next);
61   }
62 }
63 
64 void valid(FMOD_RESULT result, string msg = null) {
65   if (result != FMOD_RESULT.FMOD_OK) {
66     throw new FMODException(result, msg);
67   }
68 }
69 
70 void loadFMOD() {
71   DerelictFmod.load();
72 }
73 
74 /*
75    Wraps the FMOD_System C struct
76  */
77 class System {
78   FMOD_SYSTEM *sys;
79 
80   this() {
81     this.sys = new FMOD_SYSTEM;
82     auto res = FMOD_System_Create(&this.sys);
83     valid(res);
84   }
85 
86   ~this() {
87     valid(FMOD_System_Release(this.sys));
88   }
89 
90   void setOutput(FMOD_OUTPUTTYPE output) {
91     valid(FMOD_System_SetOutput(this.sys, output));
92   }
93 
94   FMOD_OUTPUTTYPE getOutput() {
95     FMOD_OUTPUTTYPE output;
96     valid(FMOD_System_GetOutput(this.sys, &output));
97     return output;
98   }
99 
100   int getNumDrivers() {
101     int num;
102     valid(FMOD_System_GetNumDrivers(this.sys, &num));
103     return num;
104   }
105 
106   void setDriver(int driver) {
107     valid(FMOD_System_SetDriver(this.sys, driver));
108   }
109 
110   int getDriver() {
111     int driver;
112     valid(FMOD_System_GetDriver(this.sys, &driver));
113     return driver;
114   }
115 
116   void setSoftwareChannels(int num) {
117     valid(FMOD_System_SetSoftwareChannels(this.sys, num));
118   }
119 
120   int getSoftwareChannels() {
121     int num;
122     valid(FMOD_System_GetSoftwareChannels(this.sys, &num));
123     return num;
124   }
125 
126   void setSoftwareFormat(SoftwareFormat *fmt) {
127     valid(FMOD_System_SetSoftwareFormat(this.sys, fmt.samplerate, fmt.speakermode, fmt.numrawspeakers));
128   }
129 
130   SoftwareFormat getSoftwareFormat() {
131     SoftwareFormat fmt;
132     valid(FMOD_System_GetSoftwareFormat(this.sys, &fmt.samplerate, &fmt.speakermode, &fmt.numrawspeakers));
133     return fmt;
134   }
135 
136   void setAdvancedSettings(FMOD_ADVANCEDSETTINGS *settings) {
137     valid(FMOD_System_SetAdvancedSettings(this.sys, settings));
138   }
139 
140   FMOD_ADVANCEDSETTINGS getAdvancedSettings() {
141     FMOD_ADVANCEDSETTINGS settings;
142     valid(FMOD_System_GetAdvancedSettings(this.sys, &settings));
143     return settings;
144   }
145 
146   void init(int maxchannels, uint flags=FMOD_INIT_NORMAL, void *extradriverdata=null) {
147     auto res = FMOD_System_Init(this.sys, maxchannels, flags, extradriverdata);
148     valid(res);
149   }
150 
151   void close() {
152     valid(FMOD_System_Close(this.sys));
153   }
154 
155   void update() {
156     valid(FMOD_System_Update(this.sys));
157   }
158 
159   void setSpeakerPosition(SpeakerPosition *pos) {
160     valid(FMOD_System_SetSpeakerPosition(this.sys, pos.speaker, pos.x, pos.y, cast(int)pos.active));
161   }
162 
163   SpeakerPosition getSpeakerPosition() {
164     SpeakerPosition pos;
165     int active;
166 
167     valid(FMOD_System_GetSpeakerPosition(this.sys, pos.speaker, &pos.x, &pos.y, &active));
168     pos.active = cast(bool)active;
169     return pos;
170   }
171 
172   void setStreamBufferSize(StreamBufferSize *size) {
173     valid(FMOD_System_SetStreamBufferSize(this.sys, size.filebuffersize, size.filebuffersizetype));
174   }
175 
176   StreamBufferSize getStreamBufferSize() {
177     StreamBufferSize size;
178     valid(FMOD_System_GetStreamBufferSize(this.sys, &size.filebuffersize, &size.filebuffersizetype));
179     return size;
180   }
181 
182   void set3DSettings(Settings3D *settings) {
183     valid(FMOD_System_Set3DSettings(this.sys, settings.dopplerscale, settings.distancefactor, settings.rolloffscale));
184   }
185 
186   Settings3D get3DSettings() {
187     Settings3D settings;
188     valid(FMOD_System_Get3DSettings(this.sys, &settings.dopplerscale, &settings.distancefactor, &settings.rolloffscale));
189     return settings;
190   }
191 
192   void set3DNumListeners(int num) {
193     valid(FMOD_System_Set3DNumListeners(this.sys, num));
194   }
195 
196   int get3DNumListeners() {
197     int num;
198     valid(FMOD_System_Get3DNumListeners(this.sys, &num));
199     return num;
200   }
201 
202   Sound createSound(string name_or_data, uint mode=0, FMOD_CREATESOUNDEXINFO *exinfo=null) {
203     return new Sound(this, name_or_data, mode, exinfo);
204   }
205 }
206 
207 class Sound {
208   Channel     channel;
209   FMOD_SOUND  *sound;
210 
211   this(System sys, string name, uint mode, FMOD_CREATESOUNDEXINFO *exinfo) {
212     this.sound = new FMOD_SOUND;
213     auto res1 = FMOD_System_CreateSound(sys.sys, name.ptr, mode, exinfo, &this.sound);
214     valid(res1);
215     auto res2 = FMOD_Sound_SetUserData(this.sound, cast(void*)sys);
216     valid(res2);
217   }
218 
219   ~this() {
220     valid(FMOD_Sound_Release(this.sound));
221   }
222 
223   System parent() {
224     System sys;
225     valid(FMOD_Sound_GetUserData(this.sound, cast(void**)sys));
226     return sys;
227   }
228 
229   // Get the system object for this sound
230   FMOD_SYSTEM *system() {
231     FMOD_SYSTEM *sys;
232     valid(FMOD_Sound_GetSystemObject(this.sound, &sys));
233     return sys;
234   }
235 
236   void play(FMOD_CHANNELGROUP *group=null, bool paused=false) {
237     FMOD_CHANNEL *chan;
238     auto res = FMOD_System_PlaySound(this.system, this.sound, group, cast(int)paused, &chan);
239     valid(res);
240     this.channel = new Channel(chan);
241   }
242 
243   void setDefaults(SoundDefaults *def) {
244     valid(FMOD_Sound_SetDefaults(this.sound, def.frequency, def.priority));
245   }
246 
247   SoundDefaults getDefaults() {
248     SoundDefaults def;
249     valid(FMOD_Sound_GetDefaults(this.sound, &def.frequency, &def.priority));
250     return def;
251   }
252 
253   void set3DDistance(Sound3DDistance *dist) {
254     valid(FMOD_Sound_Set3DMinMaxDistance(this.sound, dist.min, dist.max));
255   }
256 
257   Sound3DDistance get3DDistance() {
258     Sound3DDistance dist;
259     valid(FMOD_Sound_Get3DMinMaxDistance(this.sound, &dist.min, &dist.max));
260     return dist;
261   }
262 
263   void set3DConeSettings(Sound3DConeSettings *set) {
264     valid(FMOD_Sound_Set3DConeSettings(this.sound, set.insideangle, set.outsideangle, set.outsidevolume));
265   }
266 
267   Sound3DConeSettings get3DConeSettings() {
268     Sound3DConeSettings set;
269     valid(FMOD_Sound_Get3DConeSettings(this.sound, &set.insideangle, &set.outsideangle, &set.outsidevolume));
270     return set;
271   }
272 
273   void set3DCustomRolloff(FMOD_VECTOR[] points) {
274     valid(FMOD_Sound_Set3DCustomRolloff(this.sound, &points[0], cast(int)points.length));
275   }
276 
277   string getName(int length = 64) {
278     char[] str = new char[length];
279     valid(FMOD_Sound_GetName(this.sound, &str[0], length));
280     return cast(string)str;
281   }
282 
283   // Returns the length in milliseconds
284   uint getLength() {
285     uint length;
286     valid(FMOD_Sound_GetLength(this.sound, &length, FMOD_TIMEUNIT_MS));
287     return length;
288   }
289 
290   SoundFormat getFormat() {
291     SoundFormat fmt;
292     valid(FMOD_Sound_GetFormat(this.sound, fmt.type, fmt.format, &fmt.channels, &fmt.bits));
293     return fmt;
294   }
295 
296   float getMusicSpeed() {
297     float speed;
298     valid(FMOD_Sound_GetMusicSpeed(this.sound, &speed));
299     return speed;
300   }
301 
302   void setMusicSpeed(float speed) {
303     valid(FMOD_Sound_SetMusicSpeed(this.sound, speed));
304   }
305 
306   void setMode(uint mode) {
307     valid(FMOD_Sound_SetMode(this.sound, mode));
308   }
309 
310   uint getMode() {
311     uint mode;
312     valid(FMOD_Sound_GetMode(this.sound, &mode));
313     return mode;
314   }
315 
316   int getLoopCount() {
317     int count;
318     valid(FMOD_Sound_GetLoopCount(this.sound, &count));
319     return count;
320   }
321 
322   void setLoopCount(int count) {
323     valid(FMOD_Sound_SetLoopCount(this.sound, count));
324   }
325 }
326 
327 class Channel {
328   FMOD_CHANNEL *channel;
329 
330   this(FMOD_CHANNEL *chan) {
331     this.channel = chan;
332   }
333 
334   FMOD_SYSTEM *system() {
335     FMOD_SYSTEM *sys;
336     valid(FMOD_Channel_GetSystemObject(this.channel, &sys));
337     return sys;
338   }
339 
340   void stop() {
341     valid(FMOD_Channel_Stop(this.channel));
342   }
343 
344   void setPaused(bool paused) {
345     valid(FMOD_Channel_SetPaused(this.channel, cast(int)paused));
346   }
347 
348   bool getPaused() {
349     int paused;
350     valid(FMOD_Channel_GetPaused(this.channel, &paused));
351     return cast(bool)paused;
352   }
353 
354   void setVolume(float volume) {
355     valid(FMOD_Channel_SetVolume(this.channel, volume));
356   }
357 
358   float getVolume() {
359     float volume;
360     valid(FMOD_Channel_GetVolume(this.channel, &volume));
361     return volume;
362   }
363 
364   void setVolumeRamp(int ramp) {
365     valid(FMOD_Channel_SetVolumeRamp(this.channel, ramp));
366   }
367 
368   int getVolumeRamp() {
369     int ramp;
370     valid(FMOD_Channel_GetVolumeRamp(this.channel, &ramp));
371     return ramp;
372   }
373 
374   float getAudibility() {
375     float aud;
376     valid(FMOD_Channel_GetAudibility(this.channel, &aud));
377     return aud;
378   }
379 
380   void setPitch(float pitch) {
381     valid(FMOD_Channel_SetPitch(this.channel, pitch));
382   }
383 
384   float getPitch() {
385     float pitch;
386     valid(FMOD_Channel_GetPitch(this.channel, &pitch));
387     return pitch;
388   }
389 
390   void setMute(bool mute) {
391     valid(FMOD_Channel_SetMute(this.channel, cast(int)mute));
392   }
393 
394   bool getMute() {
395     int mute;
396     valid(FMOD_Channel_GetMute(this.channel, &mute));
397     return cast(bool)mute;
398   }
399 
400   float getReverbProperties(int instance) {
401     float wet;
402     valid(FMOD_Channel_GetReverbProperties(this.channel, instance, &wet));
403     return wet;
404   }
405 
406   void setReverbProperties(int instance, float wet) {
407     valid(FMOD_Channel_SetReverbProperties(this.channel, instance, wet));
408   }
409 
410   void setLowPassGain(float gain) {
411     valid(FMOD_Channel_SetLowPassGain(this.channel, gain));
412   }
413 
414   float getLowPassGain() {
415     float gain;
416     valid(FMOD_Channel_GetLowPassGain(this.channel, &gain));
417     return gain;
418   }
419 }
420 
421 unittest {
422   loadFMOD();
423   System sys = new System();
424   sys.init(10);
425   delete(sys);
426 }
427