initial commit
[liquidmodel] / src / music.c
1 #ifndef NO_AUDIO
2
3 #include <stdio.h>
4 #include <sys/stat.h>
5 #include "music.h"
6 #include "assfile.h"
7 #include "miniaudio/miniaudio.h"
8
9 static const char *fmtname(ma_format fmt);
10 static ma_result vopen(ma_vfs *vfs, const char *path, ma_uint32 mode, ma_vfs_file *fret);
11 static ma_result vclose(ma_vfs *vfs, ma_vfs_file fp);
12 static ma_result vread(ma_vfs *vfs, ma_vfs_file fp, void *dest, size_t sz, size_t *numread);
13 static ma_result vseek(ma_vfs *vfs, ma_vfs_file fp, ma_int64 offs, ma_seek_origin from);
14 static ma_result vtell(ma_vfs *vfs, ma_vfs_file fp, ma_int64 *pos);
15 static ma_result vinfo(ma_vfs *vfs, ma_vfs_file fp, ma_file_info *inf);
16
17 static int init_done;
18 static ma_engine engine;
19 static ma_sound sound;
20 static ma_resource_manager resman;
21 static ma_uint32 sample_rate;
22 static float volume;
23
24 static ma_vfs_callbacks vfs = {
25         vopen, 0,
26         vclose,
27         vread, 0,
28         vseek,
29         vtell,
30         vinfo
31 };
32
33 int init_music(void)
34 {
35         ma_engine_config engcfg;
36         ma_resource_manager_config rescfg;
37         unsigned int flags;
38         ma_format fmt;
39         ma_uint32 nchan;
40
41         rescfg = ma_resource_manager_config_init();
42         rescfg.pVFS = &vfs;
43         if(ma_resource_manager_init(&rescfg, &resman) != 0) {
44                 fprintf(stderr, "failed to initialize miniaudio resource manager\n");
45                 return -1;
46         }
47
48         engcfg = ma_engine_config_init();
49         engcfg.pResourceManager = &resman;
50
51         if(ma_engine_init(&engcfg, &engine) != 0) {
52                 fprintf(stderr, "failed to initialize miniaudio engine\n");
53                 return -1;
54         }
55
56         /*
57         flags = MA_SOUND_FLAG_STREAM;
58         if(ma_sound_init_from_file(&engine, "data/woodclick.wav", flags, 0, 0, &sound) != 0) {
59                 fprintf(stderr, "failed to load music\n");
60                 return -1;
61         }
62         ma_sound_get_data_format(&sound, &fmt, &nchan, &sample_rate, 0, 0);
63         printf("loaded sound: %s %u.%03u khz, %u channels\n", fmtname(fmt),
64                         (unsigned int)sample_rate / 1000, (unsigned int)sample_rate % 1000,
65                         (unsigned int)nchan);
66         */
67
68         init_done = 1;
69         volume = 1.0f;
70         return 0;
71 }
72
73 void destroy_music(void)
74 {
75         if(init_done) {
76                 ma_sound_stop(&sound);
77                 ma_sound_uninit(&sound);
78                 ma_engine_uninit(&engine);
79         }
80         init_done = 0;
81 }
82
83 void play_music(void)
84 {
85         if(init_done) {
86                 ma_sound_start(&sound);
87         }
88 }
89
90 void stop_music(void)
91 {
92         if(init_done) {
93                 ma_sound_stop(&sound);
94         }
95 }
96
97 void seek_music(long tm)
98 {
99         ma_uint64 frm;
100
101         if(init_done) {
102                 if(tm < 0) tm = 0;
103                 frm = (ma_uint64)tm * (ma_uint64)sample_rate / 1000llu;
104                 ma_sound_seek_to_pcm_frame(&sound, frm);
105         }
106 }
107
108 void set_music_volume(float vol)
109 {
110         if(init_done) {
111                 volume = vol;
112                 ma_engine_set_volume(&engine, vol);
113         }
114 }
115
116
117 static const char *fmtname(ma_format fmt)
118 {
119         switch(fmt) {
120         case ma_format_u8: return "8 bit";
121         case ma_format_s16: return "16 bit";
122         case ma_format_s24: return "24 bit";
123         case ma_format_s32: return "32 bit";
124         case ma_format_f32: return "float";
125         default:
126                 return "unknown";
127         }
128 }
129
130 static ma_result vopen(ma_vfs *vfs, const char *path, ma_uint32 mode, ma_vfs_file *fret)
131 {
132         ass_file *fp;
133
134         if(mode != MA_OPEN_MODE_READ) return -1;
135
136         if(!(fp = ass_fopen(path, "rb"))) {
137                 return -1;
138         }
139         *fret = fp;
140         return 0;
141 }
142
143 static ma_result vclose(ma_vfs *vfs, ma_vfs_file fp)
144 {
145         ass_fclose(fp);
146         return 0;
147 }
148
149 static ma_result vread(ma_vfs *vfs, ma_vfs_file fp, void *dest, size_t sz, size_t *numread)
150 {
151         size_t res;
152
153         res = ass_fread(dest, 1, sz, fp);
154         if(numread) *numread = res;
155
156         if(res != sz) {
157                 if(res == 0) return MA_AT_END;
158         }
159         return MA_SUCCESS;
160 }
161
162 static ma_result vseek(ma_vfs *vfs, ma_vfs_file fp, ma_int64 offs, ma_seek_origin org)
163 {
164         int from;
165         switch(org) {
166         case ma_seek_origin_start:
167                 from = SEEK_SET;
168                 break;
169         case ma_seek_origin_current:
170                 from = SEEK_CUR;
171                 break;
172         case ma_seek_origin_end:
173                 from = SEEK_END;
174                 break;
175         }
176         return ass_fseek(fp, offs, from) == -1 ? -1 : 0;
177 }
178
179 static ma_result vtell(ma_vfs *vfs, ma_vfs_file fp, ma_int64 *pos)
180 {
181         *pos = ass_ftell(fp);
182         return 0;
183 }
184
185 static ma_result vinfo(ma_vfs *vfs, ma_vfs_file fp, ma_file_info *inf)
186 {
187         int fd;
188         struct stat st;
189
190 #ifdef _MSC_VER
191         fd = _fileno(fp);
192 #else
193         fd = fileno(fp);
194 #endif
195
196         if(fstat(fd, &st) != 0) {
197                 return MA_ERROR;
198         }
199         inf->sizeInBytes = st.st_size;
200         return MA_SUCCESS;
201 }
202
203 #else   /* NO_AUDIO */
204
205 int init_music(void)
206 {
207         return 0;
208 }
209
210 void destroy_music(void)
211 {
212 }
213
214 void play_music(void)
215 {
216 }
217
218 void stop_music(void)
219 {
220 }
221
222 void seek_music(long tm)
223 {
224 }
225
226
227 void set_music_volume(float vol)
228 {
229 }
230
231 #endif