1 module d2d.audio.music; 2 3 import d2d; 4 5 /// 1.0 / MIX_MAX_VOLUME 6 enum INV_MIX_MAX_VOLUME = 1.0f / MIX_MAX_VOLUME; 7 8 /// 9 enum FadingStatus : ubyte 10 { 11 /// 12 NoFading = MIX_NO_FADING, 13 /// 14 FadingOut = MIX_FADING_OUT, 15 /// 16 FadingIn = MIX_FADING_IN, 17 } 18 19 /// 20 enum MusicType : ubyte 21 { 22 /// 23 CommandBased = MUS_CMD, 24 /// 25 Wav = MUS_WAV, 26 /// 27 Mod = MUS_MOD, 28 /// 29 ModPlug = MUS_MODPLUG, 30 /// 31 Mid = MUS_MID, 32 /// 33 Ogg = MUS_OGG, 34 /// 35 Mp3 = MUS_MP3, 36 /// 37 Mp3Mad = MUS_MP3_MAD, 38 /// 39 None = MUS_NONE, 40 } 41 42 /// Thin wrap around Mix_Music including loading [FLAC, MikMod, Ogg Vorbis, MP3, Wav] using SDL_Mixer. 43 class Music : IVerifiable, IDisposable 44 { 45 private Mix_Music* _handle; 46 47 /// Handle to the `Mix_Music*`. 48 public @property Mix_Music* handle() 49 { 50 return _handle; 51 } 52 53 /// Checks if the handle is not null. 54 public @property bool valid() 55 { 56 return _handle !is null; 57 } 58 59 private this(Mix_Music * handle) 60 { 61 _handle = handle; 62 } 63 64 /// Loads a music file 65 public this(string path) 66 { 67 _handle = Mix_LoadMUS(path.toStringz()); 68 } 69 70 public ~this() 71 { 72 dispose(); 73 } 74 75 /// Creates music from a `Mix_Music*`. 76 public static Music fromMusic(Mix_Music* handle) 77 { 78 return new Music(handle); 79 } 80 81 public static bool load() 82 { 83 return Mix_OpenAudio(44_100, MIX_DEFAULT_FORMAT, 2, 4096) == 0; 84 } 85 86 /// Returns the latest sound related error 87 public static @property string error() 88 { 89 return cast(string) Mix_GetError().fromStringz(); 90 } 91 92 /// Deallocates the memory and invalidates `this`. 93 public void dispose() 94 { 95 if (valid) 96 { 97 stop(); 98 Mix_FreeMusic(_handle); 99 _handle = null; 100 } 101 } 102 103 /// Plays this music, will stop other musics. -1 loops will play forever. 104 /// Returns: true on success, or false on errors 105 public bool play(int loops = 1) 106 { 107 return Mix_PlayMusic(_handle, loops) == 0; 108 } 109 110 /// Starts this music by fading in over `ms` milliseconds, will stop other musics. -1 loops will play forever. 111 /// Params: 112 /// ms = Milliseconds for the fade-in effect to complete. 113 /// loops = -1 loops will play forever. 0 plays the music zero times. 114 /// Returns: true on success, or false on errors 115 public bool fadeIn(int ms, int loops = 1) 116 { 117 return Mix_FadeInMusic(_handle, loops, ms) == 0; 118 } 119 120 /// Starts this music by fading in over `ms` milliseconds, will stop other musics. 121 /// Params: 122 /// ms = Milliseconds for the fade-in effect to complete. 123 /// loops = -1 loops will play forever. 0 plays the music zero times. 124 /// position = Set the position of the currently playing music. The position takes different meanings for different music sources. It only works on the music sources listed below. 125 /// <b>MOD</b> 126 /// The double is cast to Uint16 and used for a pattern number in the module. Passing zero is similar to rewinding the song. 127 /// <b>OGG/MP3</b> 128 /// Jumps to position seconds from the beginning of the song. 129 /// Returns: true on success, or false on errors 130 public bool fadeIn(int ms, int loops, double position) 131 { 132 return Mix_FadeInMusicPos(_handle, loops, ms, position) == 0; 133 } 134 135 /// 136 public @property MusicType type() 137 { 138 return cast(MusicType) Mix_GetMusicType(_handle); 139 } 140 141 /// Modifies the position where currently playing. 142 /// Params: 143 /// value = Set the position of the currently playing music. The position takes different meanings for different music sources. It only works on the music sources listed below. Will automatically rewind before setting. 144 /// <b>MOD</b> 145 /// The double is cast to Uint16 and used for a pattern number in the module. Passing zero is similar to rewinding the song. 146 /// <b>OGG/MP3</b> 147 /// Jumps to position seconds from the beginning of the song. 148 /// Returns: true on success, or false if the codec doesn't support this function 149 public static @property bool position(double value) 150 { 151 Mix_RewindMusic(); 152 return Mix_SetMusicPosition(value) == 0; 153 } 154 155 /// Rewinds music to the start. This is safe to use on halted, paused, and already playing music. It is not useful to rewind the music immediately after starting playback, because it starts at the beginning by default. 156 public static void rewind() 157 { 158 Mix_RewindMusic(); 159 } 160 161 /// Halt playback of music. This interrupts music fader effects. 162 public static void stop() 163 { 164 Mix_RewindMusic(); 165 } 166 167 /// Pause the music playback. You may halt paused music. 168 /// Note: Music can only be paused if it is actively playing. 169 public static void pause() 170 { 171 Mix_PauseMusic(); 172 } 173 174 /// Unpause the music. This is safe to use on halted, paused, and already playing music. 175 public static void resume() 176 { 177 Mix_ResumeMusic(); 178 } 179 180 /// Returns the current volume as float in range 0.0 to 1.0 181 public static @property float volume() 182 { 183 return Mix_VolumeMusic(-1) * INV_MIX_MAX_VOLUME; 184 } 185 186 /// Sets the current volume as float in range 0.0 to 1.0 187 public static @property void volume(float value) 188 { 189 Mix_VolumeMusic(cast(int) (value * MIX_MAX_VOLUME)); 190 } 191 192 /// 193 public static @property bool isPlaying() 194 { 195 return Mix_PlayingMusic() == 1; 196 } 197 198 /// 199 public static @property bool isPaused() 200 { 201 return Mix_PausedMusic() == 1; 202 } 203 204 /// 205 public static @property FadingStatus fadingStatus() 206 { 207 return cast(FadingStatus) Mix_FadingMusic(); 208 } 209 }