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