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