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 }