1 module d2d.audio.sound; 2 3 import d2d; 4 5 /// Thin wrap around Mix_Chunk including loading [FLAC, MikMod, Ogg Vorbis, MP3, Wav] using SDL_Mixer. 6 class Sound : IVerifiable, IDisposable 7 { 8 private Mix_Chunk* _handle; 9 10 /// Handle to the `Mix_Chunk*`. 11 public @property Mix_Chunk* handle() 12 { 13 return _handle; 14 } 15 16 /// Checks if the handle is not null. 17 public @property bool valid() 18 { 19 return _handle !is null; 20 } 21 22 private this(Mix_Chunk * handle) 23 { 24 _handle = handle; 25 } 26 27 /// Loads a sound file 28 public this(string path) 29 { 30 // Confusing name, this can load any format 31 _handle = Mix_LoadWAV(path.toStringz()); 32 } 33 34 public ~this() 35 { 36 dispose(); 37 } 38 39 /// Creates sound from a `Mix_Chunk*`. 40 public static Sound fromChunk(Mix_Chunk* chunk) 41 { 42 return new Sound(chunk); 43 } 44 45 /// Returns the latest sound related error 46 public static @property string error() 47 { 48 return cast(string) Mix_GetError().fromStringz(); 49 } 50 51 /// Deallocates the memory and invalidates `this`. 52 public void dispose() 53 { 54 if (valid) 55 { 56 stop(); 57 Mix_FreeChunk(_handle); 58 _handle = null; 59 } 60 } 61 62 /// Plays this sound in the selected channel. 63 /// Params: 64 /// loops = -1 loops will play forever. 0 plays once. 65 /// channel = -1 loops will choose the first free unreserved channel. 66 /// maxTicks = Maximum milliseconds to play this sound. If not enough loops or the sample chunk is not long enough, then the sample may stop before this timeout occurs. -1 means play forever. 67 /// Returns: the channel the sample is played on. On any errors, -1 is returned. 68 public int play(int loops = 0, int channel = -1, int maxTicks = -1) 69 { 70 return Mix_PlayChannelTimed(channel, _handle, loops, maxTicks); 71 } 72 73 /// Plays this sound in the selected channel with a fade in effect. 74 /// Params: 75 /// ms = Milliseconds for the fade-in effect to complete. 76 /// loops = -1 loops will play forever. 0 plays once. 77 /// channel = -1 loops will choose the first free unreserved channel. 78 /// maxTicks = Maximum milliseconds to play this sound. If not enough loops or the sample chunk is not long enough, then the sample may stop before this timeout occurs. -1 means play forever. 79 /// Returns: the channel the sample is played on. On any errors, -1 is returned. 80 public int fadeIn(int ms, int loops = 1, int channel = -1, int maxTicks = -1) 81 { 82 return Mix_FadeInChannelTimed(channel, _handle, loops, ms, maxTicks); 83 } 84 85 /// Halt playback of sound. This interrupts sound fader effects. 86 /// Params: 87 /// channel = Channel to stop playing, or -1 for all channels. 88 public static void stop(int channel = -1) 89 { 90 Mix_HaltChannel(channel); 91 } 92 93 /// Pause the sound playback. You may halt paused sounds. 94 /// Params: 95 /// channel = Channel to stop playing, or -1 for all channels. 96 /// Note: Sound can only be paused if it is actively playing. 97 public static void pause(int channel = -1) 98 { 99 Mix_Pause(channel); 100 } 101 102 /// Unpause the sound. This is safe to use on halted, paused, and already playing sounds. 103 /// Params: 104 /// channel = Channel to stop playing, or -1 for all channels. 105 public static void resume(int channel = -1) 106 { 107 Mix_Resume(channel); 108 } 109 110 /// Returns the current volume as float in range 0.0 to 1.0 111 /// Params: 112 /// channel = -1 for all channels. 113 public static float getVolume(int channel = -1) 114 { 115 return Mix_Volume(channel, -1) * INV_MIX_MAX_VOLUME; 116 } 117 118 /// Sets the current volume as float in range 0.0 to 1.0 119 /// Params: 120 /// value = volume between 0.0 and 1.0. 121 /// channel = -1 for all channels. 122 public static void setVolume(float value, int channel = -1) 123 { 124 Mix_Volume(channel, cast(int) (value * MIX_MAX_VOLUME)); 125 } 126 127 /// Tells you how many channels are playing if set to -1 128 /// Params: 129 /// channel = -1 for all channels. 130 public static @property int isPlaying(int channel = -1) 131 { 132 return Mix_Playing(channel); 133 } 134 135 /// Tells you how many channels are paused if set to -1 136 /// Params: 137 /// channel = -1 for all channels. 138 public static @property int isPaused(int channel = -1) 139 { 140 return Mix_Paused(channel); 141 } 142 143 /// 144 /// Params: 145 /// channel = -1 is invalid. 146 public static @property FadingStatus fadingStatus(int channel) 147 { 148 assert(channel != -1); 149 return cast(FadingStatus) Mix_FadingChannel(channel); 150 } 151 }