1 /// Part of my old D1 game library along with [arsd.screen] and [arsd.engine]. Do not use in new projects.
2 module arsd.audio;
3 
4 import sdl.SDL;
5 import sdl.SDL_mixer;
6 
7 import arsd.engine;
8 
9 bool audioIsLoaded; // potential hack material
10 
11 class Sound {
12   public:
13 	this(char[] filename){
14 		if(!audioIsLoaded)
15 			return;
16 		sfx = Mix_LoadWAV((filename ~ "\0").ptr);
17 		if(sfx is null)
18 			throw new Exception(immutableString("Sound load " ~ filename));
19 	}
20 
21 	/*
22 	this(Wav wav){
23 		auto w = wav.toMemory;
24 		SDL_RWops* a = SDL_RWFromMem(w, w.length)
25 		if(a is null) throw new Exception("sdl rw ops");
26 		scope(exit) SDL_FreeRW(a);
27 		sfx = Mix_LoadWAV_RW(a, 0);
28 		if(sfx is null) throw new Exception("loadwav rw");
29 	}
30 	*/
31 
32 	~this(){
33 		if(sfx !is null)
34 			Mix_FreeChunk(sfx);
35 	}
36 
37   private:
38 	Mix_Chunk* sfx;
39 }
40 
41 class Music {
42   public:
43 	this(char[] filename){
44 		if(!audioIsLoaded)
45 			return;
46 		mus = Mix_LoadMUS((filename~"\0").ptr);
47 		if(mus is null)
48 			throw new Exception(immutableString("Music load " ~ filename));
49 	}
50 
51 	~this(){
52 		if(mus !is null)
53 			Mix_FreeMusic(mus);
54 	}
55   private:
56 	Mix_Music* mus;
57 }
58 
59 class Audio{
60   public:
61 	this(bool act = true){
62 		if(audioIsLoaded)
63 			throw new Exception("Cannot load audio twice");
64 
65 		if(!act){
66 			audioIsLoaded = false;
67 			active = false;
68 			return;
69 		}
70 		if(Mix_OpenAudio(22050, AUDIO_S16SYS, 2, 4096/2 /* the /2 is new */) != 0){
71 			active = false; //throw new Error;
72 			error = true;
73 			audioIsLoaded = false;
74 		} else {
75 			active = true;
76 			error = false;
77 			audioIsLoaded = true;
78 		}
79 
80 		sfxChannel = 1;
81 
82 		careAboutErrors = false;
83 	}
84 
85 	void activate(){
86 		if(!audioIsLoaded) return;
87 		if(!error)
88 			active = true;
89 	}
90 
91 	void deactivate(){
92 		if(!audioIsLoaded) return;
93 		active = false;
94 	}
95 
96 	void toggleActivation(){
97 		if(!audioIsLoaded) return;
98 		if(error)
99 			return;
100 		active = !active;
101 	}
102 
103 	~this(){
104 		if(audioIsLoaded){
105 			Mix_HaltMusic();
106 			Mix_HaltChannel(-1);
107 			Mix_CloseAudio();
108 		}
109 	}
110 
111 	void playEffect(Sound snd, bool loop = false){
112 		if(!active || snd is null)
113 			return;
114 
115 		//if(Mix_Playing(sfxChannel))
116 		//	return;
117 
118 		sfxChannel = Mix_PlayChannel(-1, snd.sfx, loop == true ? -1 : 0);
119 
120 	}
121 	void stopEffect(){
122 		if(!active)
123 			return;
124 
125 		Mix_HaltChannel(sfxChannel);
126 	}
127 
128 	void playMusic(Music mus, bool loop = true){
129 		if(!active || mus is null)
130 			return;
131 
132 		if(Mix_PlayMusic(mus.mus, loop == true ? -1 : 0) == -1)
133 			throw new Exception("play music");
134 		//	musicIsPlaying = false;
135 		else
136 			musicIsPlaying = true;
137 	}
138 
139 	void pauseMusic(){
140 		if(!active)
141 			return;
142 
143 		if(musicIsPlaying){
144 			Mix_PauseMusic();
145 			musicIsPaused = true;
146 		}
147 	}
148 
149 	void unpauseMusic(){
150 		if(!active)
151 			return;
152 
153 		if(musicIsPaused){
154 			Mix_ResumeMusic();
155 			musicIsPaused = false;
156 		}
157 	}
158 
159 	void stopMusic(){
160 		if(!active)
161 			return;
162 
163 		Mix_HaltMusic();
164 	}
165 
166 
167 	void stopAll(){
168 		if(!active)
169 			return;
170 
171 		Mix_HaltMusic();
172 		Mix_HaltChannel(-1);
173 	}
174 
175   private:
176   	int sfxChannel;
177 	bool active;
178 	bool error;
179 
180 	bool musicIsPaused;
181 	bool musicIsPlaying;
182 
183 	bool careAboutErrors;
184 }
185 
186 	int Mix_PlayChannel(int channel, Mix_Chunk* chunk, int loops) {
187 		return Mix_PlayChannelTimed(channel,chunk,loops,-1);
188 	}
189 	Mix_Chunk * Mix_LoadWAV(in char *file) {
190 		return Mix_LoadWAV_RW(SDL_RWFromFile(file, "rb"), 1);
191 	}