1 /**
2  * Sound
3  */
4 module d2d.sdl2.Sound;
5 
6 import std.algorithm;
7 import std.conv;
8 import std..string;
9 import std.traits;
10 import d2d.sdl2;
11 
12 /**
13  * The two types of sounds there are
14  * Chunks are for sound effects and for shorter sounds
15  * Musics are for longer sounds such as background music
16  * Multiple chunks can play at once, but only one music can be playing at a time
17  */
18 enum SoundType {
19     Chunk,
20     Music
21 }
22 
23 /**
24  * A sound is, as its name suggests, something that can be played and make a noise
25  * Sounds are templated and can either be chunks or musics
26  * A chunk sound is a short sound that is usually a sound effect or something quick; many chunks can play at once
27  * A chunk will only play once
28  * A music is something that usually plays for longer and is usually something like background music; only one sound can play at once
29  * A music will loop infinitely until destroyed
30  * This sound is a primitive port from SDL and doesn't allow for much control
31  * There is no constructor for a sound from an already existing Mix_Chunk or Mix_Music because it may have unintended behaviour
32  */
33 class Sound(SoundType T) {
34 
35     mixin("private Mix_" ~ T.to!string ~ "* sound;"); ///The actual sample from SDL
36 
37     /**
38      * Returns the raw SDL data of this object
39      */
40     mixin("@property Mix_" ~ T.to!string ~ "* handle(){
41         return this.sound;
42     }");
43 
44     /**
45      * Makes the sound given the string of the path of the sound
46      * If this is a music sound, the music will loop; otherwise if this is a chunk, the chunk will play once
47      */
48     this(string soundPath) {
49         loadLibMixer();
50         static if (T == SoundType.Chunk) {
51             this.sound = ensureSafe(Mix_LoadWAV(soundPath.toStringz));
52             if (Mix_PlayChannel(-1, this.sound, 0) == -1) {
53                 ensureSafe(-1);
54             }
55         }
56         else {
57             this.sound = ensureSafe(Mix_LoadMUS(soundPath.toStringz));
58             ensureSafe(Mix_PlayMusic(this.sound, -1));
59         }
60     }
61 
62     /**
63      * Ensures that SDL can properly dispose of the chunk or music
64      */
65     mixin("~this(){
66         Mix_Free" ~ T.to!string ~ "(this.sound);
67     }");
68 }
69 
70 /** 
71  * Pauses all sounds of a type
72  * There is no implementation to pause certain sounds selectively
73  * Only the music is individually controllable
74  * For chunks, chunks are collectively paused and unpaused
75  */
76 void pause(SoundType T)() {
77     static if (T == SoundType.Chunk) {
78         Mix_Pause(-1);
79     }
80     else {
81         Mix_PauseMusic();
82     }
83 }
84 
85 /** 
86  * Resumes all sounds of a type
87  * There is no implementation to resume certain sounds selectively
88  * Only the music is individually controllable
89  * For chunks, chunks are collectively paused and unpaused
90  */
91 void resume(SoundType T)() {
92     static if (T == SoundType.Chunk) {
93         Mix_Resume(-1);
94     }
95     else {
96         Mix_ResumeMusic();
97     }
98 }
99 
100 private int _chunkVolume = MIX_MAX_VOLUME;
101 private int _musicVolume = MIX_MAX_VOLUME;
102 
103 /**
104  * Sets the volume that all chunks will play at
105  * Chunks are all at the same volume; there is no implementation to control the volume of an individual chunk
106  * TODO possibly implement Mix_VolumeChunk?
107  */
108 @property void chunkVolume(int volume) {
109     Mix_Volume(-1, volume);
110     _chunkVolume = volume;
111 }
112 
113 /**
114  * Gets the volume that all chunks will play at
115  * Chunks are all at the same volume; there is no implementation to control the volume of an individual chunk
116  * TODO possibly implement Mix_VolumeChunk?
117  */
118 @property int chunkVolume() {
119     return _chunkVolume;
120 }
121 
122 /**
123  * Sets the volume that the music will play at
124  */
125 @property void musicVolume(int volume) {
126     Mix_VolumeMusic(volume);
127     _musicVolume = volume;
128 }
129 
130 /**
131  * Gets the volume that the music will play at
132  */
133 @property int musicVolume() {
134     return _musicVolume;
135 }