backport builds
[dosdemo] / src / dos / audos.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include "audio.h"
6 #include "midasdll.h"
7 #include "util.h"
8
9 #define SET_MUS_VOL(vol) \
10         do { \
11                 int mv = (vol) * vol_master >> 10; \
12                 MIDASsetMusicVolume(modplay, mv ? mv + 1 : 0); \
13         } while(0)
14
15 extern int force_snd_config;
16
17 static MIDASmodulePlayHandle modplay;
18 static struct au_module *curmod;
19
20 static int vol_master, vol_mus, vol_sfx;
21
22 int au_init(void)
23 {
24         modplay = 0;
25         curmod = 0;
26         vol_master = vol_mus = vol_sfx = 255;
27
28         MIDASstartup();
29
30         if(force_snd_config || (!MIDASloadConfig("sound.cfg") && !MIDASdetectSoundCard())) {
31                 if(MIDASconfig()) {
32                         if(!MIDASsaveConfig("sound.cfg")) {
33                                 fprintf(stderr, "failed to save sound card configuration\n");
34                         }
35                 }
36         }
37
38         MIDASinit();
39
40         MIDASstartBackgroundPlay(0);
41         return 0;
42 }
43
44 void au_shutdown(void)
45 {
46         if(curmod) {
47                 au_stop_module(curmod);
48         }
49         MIDASstopBackgroundPlay();
50         MIDASclose();
51 }
52
53 struct au_module *au_load_module(const char *fname)
54 {
55         static MIDASmoduleInfo info;
56         struct au_module *mod;
57         char *name, *end;
58
59         if(!(mod = malloc(sizeof *mod))) {
60                 fprintf(stderr, "au_load_module: failed to allocate module\n");
61                 return 0;
62         }
63
64         if(!(mod->impl = MIDASloadModule((char*)fname))) {
65                 fprintf(stderr, "au_load_module: failed to load module: %s\n", fname);
66                 free(mod);
67                 return 0;
68         }
69
70         name = 0;
71         if(MIDASgetModuleInfo(mod->impl, &info)) {
72                 name = info.songName;
73                 end = name + strlen(name) - 1;
74                 while(end >= name && isspace(*end)) {
75                         *end-- = 0;
76                 }
77                 if(!*name) name = 0;
78         }
79
80         if(!name) {
81                 /* fallback to using the filename */
82                 if((name = strrchr(fname, '/')) || (name = strrchr(fname, '\\'))) {
83                         name++;
84                 } else {
85                         name = (char*)fname;
86                 }
87         }
88
89         if(!(mod->name = malloc(strlen(name) + 1))) {
90                 fprintf(stderr, "au_load_module: mod->name malloc failed\n");
91                 MIDASfreeModule(mod->impl);
92                 return 0;
93         }
94         strcpy(mod->name, name);
95
96         printf("loaded module \"%s\" (%s)\n", name, fname);
97         return mod;
98 }
99
100 void au_free_module(struct au_module *mod)
101 {
102         if(!mod) return;
103
104         if(mod == curmod) {
105                 au_stop_module(curmod);
106         }
107         MIDASfreeModule(mod->impl);
108         free(mod->name);
109         free(mod);
110 }
111
112 int au_play_module(struct au_module *mod)
113 {
114         if(curmod) {
115                 if(curmod == mod) return 0;
116                 au_stop_module(curmod);
117         }
118
119         if(!(modplay = MIDASplayModule(mod->impl, 1))) {
120                 fprintf(stderr, "au_play_module: failed to play module: %s\n", mod->name);
121                 return -1;
122         }
123         SET_MUS_VOL(vol_mus);
124         curmod = mod;
125         return 0;
126 }
127
128 void au_update(void)
129 {
130 }
131
132 int au_stop_module(struct au_module *mod)
133 {
134         if(mod && curmod != mod) return -1;
135         if(!curmod) return -1;
136
137         MIDASstopModule(modplay);
138         curmod = 0;
139         return 0;
140 }
141
142 int au_module_state(struct au_module *mod)
143 {
144         if(mod) {
145                 return curmod == mod ? AU_PLAYING : AU_STOPPED;
146         }
147         return curmod ? AU_PLAYING : AU_STOPPED;
148 }
149
150 int au_volume(int vol)
151 {
152         AU_VOLADJ(vol_master, vol);
153         if(vol != vol_master) {
154                 vol_master = vol;
155
156                 au_sfx_volume(vol_sfx);
157                 au_music_volume(vol_mus);
158         }
159         return vol_master;
160 }
161
162 int au_sfx_volume(int vol)
163 {
164         AU_VOLADJ(vol_sfx, vol);
165         vol_sfx = vol;
166
167         /* TODO set sfx volume */
168         return vol_sfx;
169 }
170
171
172 int au_music_volume(int vol)
173 {
174         AU_VOLADJ(vol_mus, vol);
175         vol_mus = vol;
176
177         if(curmod) {
178                 SET_MUS_VOL(vol);
179         }
180         return vol_mus;
181 }
182
183 /* when using MIDAS, we can't access the PIT directly, so we don't build timer.c
184  * and implement all the timer functions here, using MIDAS callbacks
185  */
186 static volatile unsigned long ticks;
187 static unsigned long tick_interval;
188
189 static void MIDAS_CALL midas_timer(void)
190 {
191         ticks++;
192 }
193
194 /* macro to divide and round to the nearest integer */
195 #define DIV_ROUND(a, b) \
196         ((a) / (b) + ((a) % (b)) / ((b) / 2))
197
198 void init_timer(int res_hz)
199 {
200         MIDASsetTimerCallbacks(res_hz * 1000, 0, midas_timer, 0, 0);
201         tick_interval = DIV_ROUND(1000, res_hz);
202 }
203
204 void reset_timer(void)
205 {
206         ticks = 0;
207 }
208
209 unsigned long get_msec(void)
210 {
211         return ticks * tick_interval;
212 }
213
214 void sleep_msec(unsigned long msec)
215 {
216         unsigned long wakeup_time = ticks + msec / tick_interval;
217         while(ticks < wakeup_time) {
218 #ifdef USE_HLT
219                 halt();
220 #endif
221         }
222 }