1 /*
2 * KCemu -- The emulator for the KC85 homecomputer series and much more.
3 * Copyright (C) 1997-2010 Torsten Paul
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <assert.h>
24
25 #include "libaudio/libaudioP.h"
26
27 #ifdef HAVE_LIBAUDIOFILE
28
29 #include <audiofile.h>
30
31 #define BUF_SIZE (1024)
32
33 static int af_error;
34 static char loader_name[1024];
35 static libaudio_loader_t *self = NULL;
36
37 typedef struct audio_data
38 {
39 int eof;
40 int idx;
41 int size;
42 int load_size;
43 unsigned short buf[BUF_SIZE];
44 AFfilehandle afFile;
45 } aud_data_t;
46
47 static void
loader_aud_error_func(long code,const char * str)48 loader_aud_error_func(long code, const char *str)
49 {
50 af_error = 1;
51 }
52
53 static int
loader_aud_check(const char * filename,unsigned char * data,long size)54 loader_aud_check(const char *filename, unsigned char *data, long size)
55 {
56 AFerrfunc func;
57 AFfilehandle file;
58
59 af_error = 0;
60 func = afSetErrorHandler(loader_aud_error_func);
61 file = afOpenFile(filename, "r", AF_NULL_FILESETUP);
62 afSetErrorHandler(func);
63
64 if (file == AF_NULL_FILEHANDLE)
65 return 0;
66
67 if (af_error != 0)
68 return 0;
69
70 afCloseFile(file);
71 return 1;
72 }
73
74 static libaudio_prop_t *
loader_aud_open_prop(const char * filename,libaudio_prop_t * prop)75 loader_aud_open_prop(const char *filename, libaudio_prop_t *prop)
76 {
77 int sampfmt;
78 int sampwidth;
79 aud_data_t *data;
80
81 data = (aud_data_t *)malloc(sizeof(aud_data_t));
82 if (data == NULL)
83 return NULL;
84
85 data->afFile = afOpenFile(filename, "r", AF_NULL_FILESETUP);
86 if (data->afFile == AF_NULL_FILEHANDLE)
87 {
88 free(data);
89 return NULL;
90 }
91
92 /*
93 * set the virtual sample format to 16 bit unsigned; this is
94 * exactly the format required by libaudio_read_sample()
95 */
96 afGetSampleFormat(data->afFile, AF_DEFAULT_TRACK, &sampfmt, &sampwidth);
97 if (afSetVirtualSampleFormat(data->afFile,
98 AF_DEFAULT_TRACK,
99 AF_SAMPFMT_UNSIGNED,
100 16) != 0)
101 {
102 afCloseFile(data->afFile);
103 free(data);
104 return NULL;
105 }
106
107 prop->type = LIBAUDIO_TYPE_AUD;
108 prop->loader = self;
109 prop->loader_data = data;
110
111 prop->sample_freq = (int)afGetRate(data->afFile, AF_DEFAULT_TRACK);
112 prop->sample_size = sampwidth;
113 prop->channels = afGetChannels(data->afFile, AF_DEFAULT_TRACK);
114
115 data->eof = 0;
116 data->idx = 0;
117 data->load_size = BUF_SIZE / prop->channels;
118 data->size = data->load_size;
119
120 return prop;
121 }
122
123 static libaudio_prop_t *
loader_aud_open(const char * filename)124 loader_aud_open(const char *filename)
125 {
126 libaudio_prop_t *prop, *ret;
127
128 prop = (libaudio_prop_t *)malloc(sizeof(libaudio_prop_t));
129 if (prop == NULL)
130 return NULL;
131
132 ret = loader_aud_open_prop(filename, prop);
133 if (ret == NULL)
134 free(prop);
135
136 return ret;
137 }
138
139 static void
loader_aud_close(libaudio_prop_t * prop)140 loader_aud_close(libaudio_prop_t *prop)
141 {
142 aud_data_t *data;
143
144 assert(prop != NULL);
145 assert(prop->type == LIBAUDIO_TYPE_AUD);
146 assert(prop->loader_data != NULL);
147
148 data = (aud_data_t *)prop->loader_data;
149 afCloseFile(data->afFile);
150 free(data);
151 }
152
153 static libaudio_prop_t *
loader_aud_rewind(libaudio_prop_t * prop)154 loader_aud_rewind(libaudio_prop_t *prop)
155 {
156 assert(prop != NULL);
157 assert(prop->type == LIBAUDIO_TYPE_AUD);
158 assert(prop->loader_data != NULL);
159
160 loader_aud_close(prop);
161 return loader_aud_open_prop(prop->filename, prop);
162 }
163
164 static int
loader_aud_read_sample(libaudio_prop_t * prop)165 loader_aud_read_sample(libaudio_prop_t *prop)
166 {
167 int c, len;
168 aud_data_t *data;
169
170 assert(prop != NULL);
171 assert(prop->type == LIBAUDIO_TYPE_AUD);
172 assert(prop->loader_data != NULL);
173
174 data = (aud_data_t *)prop->loader_data;
175
176 if (data->eof)
177 return EOF;
178
179 if (data->idx >= data->size)
180 {
181 len = afReadFrames(data->afFile, AF_DEFAULT_TRACK, data->buf, data->load_size);
182 if (len == 0)
183 {
184 data->eof = 1;
185 return EOF;
186 }
187 data->idx = 0;
188 data->size = len * prop->channels;
189 }
190
191 c = ((unsigned short *)data->buf)[data->idx];
192
193 data->idx++;
194 return c;
195 }
196
197 static const char *
loader_aud_get_type(void)198 loader_aud_get_type(void)
199 {
200 return "AUDIOFILE";
201 }
202
203 static const char *
loader_aud_get_name(void)204 loader_aud_get_name(void)
205 {
206 return loader_name;
207 }
208
209 static libaudio_loader_t loader = {
210 loader_aud_check,
211 loader_aud_open,
212 loader_aud_rewind,
213 loader_aud_close,
214 loader_aud_read_sample,
215 loader_aud_get_type,
216 loader_aud_get_name
217 };
218
219 void
loader_aud_init(void)220 loader_aud_init(void)
221 {
222 snprintf(loader_name,
223 sizeof(loader_name),
224 "loader for audio files supported by libaudiofile v%d.%d",
225 LIBAUDIOFILE_MAJOR_VERSION,
226 LIBAUDIOFILE_MINOR_VERSION);
227
228 if (libaudio_register_loader(&loader))
229 self = &loader;
230 }
231
232 #else /* HAVE_LIBAUDIOFILE */
233
234 void
loader_aud_init(void)235 loader_aud_init(void)
236 {
237 }
238
239 #endif /* HAVE_LIBAUDIOFILE */
240