1 /*
2  *******************************************************************************************
3  * Dgame (a D game framework) - Copyright (c) Randy Schütt
4  * 
5  * This software is provided 'as-is', without any express or implied warranty.
6  * In no event will the authors be held liable for any damages arising from
7  * the use of this software.
8  * 
9  * Permission is granted to anyone to use this software for any purpose,
10  * including commercial applications, and to alter it and redistribute it
11  * freely, subject to the following restrictions:
12  * 
13  * 1. The origin of this software must not be misrepresented; you must not claim
14  *    that you wrote the original software. If you use this software in a product,
15  *    an acknowledgment in the product documentation would be appreciated but is
16  *    not required.
17  * 
18  * 2. Altered source versions must be plainly marked as such, and must not be
19  *    misrepresented as being the original software.
20  * 
21  * 3. This notice may not be removed or altered from any source distribution.
22  *******************************************************************************************
23  */
24 module Dgame.Audio.Music;
25 
26 private:
27 
28 import derelict.sdl2.mixer;
29 
30 import Dgame.Internal.Error;
31 
32 public:
33 
34 /**
35 * Music represents the functionality to load and play music files.
36 *
37 * Note: Music is designed to load and play <b>larger</b> music files, e.g. background music
38 *       If you just want to play short sounds, use Sound.
39 *
40 * Supported formats are .wav, .mp3, .vorbis, .ogg, .midi
41 *
42 * Author: Randy Schuett (rswhite4@googlemail.com)
43 */
44 struct Music {
45 private:
46     Mix_Music* _music;
47 
48 public:
49     /**
50      * CTor
51      */
52     @nogc
53     this(string filename, ubyte volume = 128) nothrow {
54         this.loadFromFile(filename);
55         this.setVolume(volume);
56     }
57     
58     /**
59      * Postblit is disabled
60      */
61     @disable
62     this(this);
63 
64     /**
65      * DTor
66      */
67     @nogc
68     ~this() nothrow {
69         Mix_FreeMusic(_music);
70     }
71 
72     /**
73      * Load the music file (filename).
74      * Returns if the loading was successful.
75      * If not, an error message is showed which describes what the problem is.
76      */
77     @nogc
78     bool loadFromFile(string filename) nothrow {
79         _music = Mix_LoadMUS(filename.ptr);
80         if (!_music) {
81             print_fmt("Could not load file: %s\n", Mix_GetError());
82             return false;
83         }
84 
85         return true;
86     }
87 
88     /**
89      * Set the volume, max. is 128, min. is 0
90      * If the value is above 128, the max. will be assumed.
91      * Returns the previous volume.
92      */
93     @nogc
94     ubyte setVolume(ubyte volume) const nothrow {
95         return cast(ubyte) Mix_VolumeMusic(volume);
96     }
97 
98     /**
99      * Returns the current volume
100      */
101     @nogc
102     ubyte getVolume() const nothrow {
103         return cast(ubyte) Mix_VolumeMusic(-1);
104     }
105 
106     /**
107      * Plays the music.
108      * loops describe how often the music shall be played.
109      * A value of -1 indicated, that the music plays forever,
110      * a value of 0 means, that the music plays zero times.
111      * delay is the time in ms to fade in.
112      * Any previous music will be halted.
113      */
114     @nogc
115     void play(byte loops = 1, short delay = -1) nothrow {
116         if (_music) {
117             loops = loops > 0 ? cast(byte)(loops - 1) : loops;
118             Mix_FadeInMusic(_music, loops, delay);
119         }
120     }
121 
122     /**
123      * Resume the music playback
124      *
125      * See: pause
126      * See: stop
127      */
128     @nogc
129     void resume() const nothrow {
130         Mix_ResumeMusic();
131     }
132 
133     /**
134      * Stop/Halt the music playback
135      *
136      * See: resume
137      */
138     @nogc
139     void stop() const nothrow {
140         Mix_HaltMusic();
141     }
142 
143     /**
144      * Pause the music playback
145      *
146      * See: resume
147      */
148     @nogc
149     void pause() const nothrow {
150         Mix_PauseMusic();
151     }
152 
153     /**
154      * Rewind the music to the start
155      *
156      * Note: This function only works for .ogg, .vorbis, .mp3, .midi
157      */
158     @nogc
159     void rewind() const nothrow {
160         Mix_RewindMusic();
161     }
162 
163     /**
164      * Fade out the music. The music will be stopped in ms milliseconds.
165      */
166     @nogc
167     void fadeOut(ushort ms) nothrow {
168         Mix_FadeOutMusic(ms);
169     }
170 
171     /**
172      * Set the position of the currently playing music.
173      * The position takes different meanings for different music sources.
174      * 
175      * <b>.ogg / .vorbis:</b>
176      *   Jumps to position seconds from the beginning of the song.
177      * <b>mp3:</b>
178      *    Jumps to position seconds from the current position in the stream.
179      *    So you may want to call rewind before.
180      *    <b>Does not go in reverse: negative values do nothing.</b>
181      * 
182      * Note: This only works for.ogg, .vorbis and .mp3
183      */
184     @nogc
185     void setPosition(float seconds) const nothrow {
186         Mix_SetMusicPosition(seconds);
187     }
188 
189     /**
190      * Returns if the music is currently playing
191      */
192     @nogc
193     bool isPlaying() const nothrow {
194         return Mix_PlayingMusic() != 0;
195     }
196 
197     /**
198      * Returns if the music is currently paused
199      */
200     @nogc
201     bool isPaused() const nothrow {
202         return Mix_PausedMusic() != 0;
203     }
204 }