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