1 #include <config.h>
2 #ifdef SIMAGE_LIBSNDFILE_SUPPORT
3
4 #include <simage.h>
5 #include <simage_private.h>
6 #include <simage_libsndfile.h>
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <assert.h>
11
12 #include <sndfile.h>
13
14 typedef struct {
15 SNDFILE *file;
16 SF_INFO sfinfo;
17 double *tempbuffer;
18 int tempbuffersize;
19 } libsndfile_context;
20
21 static void
libsndfile_init_context(libsndfile_context * context)22 libsndfile_init_context(libsndfile_context *context)
23 {
24 context->file = NULL;
25 context->tempbuffer = NULL;
26 context->tempbuffersize = 0;
27 }
28
29 static void
libsndfile_cleanup_context(libsndfile_context * context)30 libsndfile_cleanup_context(libsndfile_context *context)
31 {
32 if (context->tempbuffer)
33 free(context->tempbuffer);
34 context->tempbuffer = NULL;
35 context->tempbuffersize = 0;
36 }
37
38 int
libsndfile_stream_open(const char * filename,s_stream * stream,s_params * params)39 libsndfile_stream_open(const char * filename, s_stream * stream,
40 s_params * params)
41 {
42 libsndfile_context *context;
43 FILE *dummyfile;
44
45 dummyfile = fopen(filename, "rb");
46 if (!dummyfile)
47 return 0;
48 else
49 fclose(dummyfile);
50
51 context = (libsndfile_context *) malloc(sizeof(libsndfile_context));
52 libsndfile_init_context(context);
53
54 context->file = sf_open (filename, SFM_READ, &context->sfinfo) ;
55 if (!context->file) {
56 libsndfile_cleanup_context(context);
57 free(context);
58 return 0;
59 }
60 sf_command (context->file, SFC_SET_NORM_DOUBLE, NULL, SF_TRUE) ;
61
62 s_stream_context_set(stream, (void *)context);
63
64 /* FIXME: SF_INFO::frames is of type sf_count_t, which is a 32bit
65 integer in some libsndfile version and 64bit on others (like the
66 Mac OS X one), so casting context->sfinfo.frames to int is not
67 totally correct - but necessary, since we do not have a 64bit
68 s_params type.
69 20030108 kyrah
70 */
71 s_params_set(s_stream_params(stream),
72 "samplerate", S_INTEGER_PARAM_TYPE, context->sfinfo.samplerate,
73 "frames", S_INTEGER_PARAM_TYPE, (int) context->sfinfo.frames,
74 "channels", S_INTEGER_PARAM_TYPE, context->sfinfo.channels,
75 NULL);
76
77 return 1;
78 }
79
80 void *
libsndfile_stream_get(s_stream * stream,void * buffer,int * size,s_params * params)81 libsndfile_stream_get(s_stream * stream, void * buffer, int * size, s_params * params)
82 {
83 int itemsread;
84 libsndfile_context *context;
85 int items;
86 int itemssize;
87 int i;
88 short int *intbuffer;
89
90 context = (libsndfile_context *)s_stream_context_get(stream);
91
92 if (context != NULL) {
93 /* fixme 20020924 thammer : support other (return) formats
94 * than 16 bit signed. This should be very little work!
95 */
96
97 /*
98 * size must be an integer multiple of bytespersample*channels
99 */
100
101 if ( (*size) % (2 * context->sfinfo.channels) ) {
102 *size = 0;
103 return NULL;
104 }
105
106 items = *size / 2;
107 itemssize = items*sizeof(double);
108
109 if (context->tempbuffersize < itemssize) {
110 if (context->tempbuffer)
111 free(context->tempbuffer);
112 context->tempbuffer = (double *)malloc(itemssize);
113 }
114
115 intbuffer = (short int*)buffer;
116 itemsread = sf_read_double(context->file, context->tempbuffer, items);
117 for (i=0; i<itemsread; i++) {
118 intbuffer[i] = context->tempbuffer[i] * (double)32767.0;
119 }
120
121 if (itemsread > 0) {
122 *size = itemsread * 2;
123 return buffer;
124 }
125
126 /* fixme 20020924 thammer: check params for conversion requests
127 */
128 }
129 *size = 0;
130 return NULL;
131 }
132
133 void
libsndfile_stream_close(s_stream * stream)134 libsndfile_stream_close(s_stream * stream)
135 {
136 libsndfile_context *context;
137 context = (libsndfile_context *)s_stream_context_get(stream);
138 if (context != NULL) {
139 sf_close(context->file);
140 context->file = NULL;
141 }
142 libsndfile_cleanup_context(context);
143 free(context);
144 }
145
146 int
libsndfile_stream_seek(s_stream * stream,int offset,int whence,s_params * params)147 libsndfile_stream_seek(s_stream * stream, int offset, int whence,
148 s_params *params)
149 {
150 libsndfile_context *context;
151 context = (libsndfile_context *)s_stream_context_get(stream);
152 if (context != NULL) {
153 return sf_seek(context->file, offset, whence);
154 }
155 else
156 return -1;
157 }
158
159 int
libsndfile_stream_tell(s_stream * stream,s_params * params)160 libsndfile_stream_tell(s_stream * stream, s_params *params)
161 {
162 libsndfile_context *context;
163 context = (libsndfile_context *)s_stream_context_get(stream);
164 if (context != NULL) {
165 return sf_seek(context->file, 0, SEEK_CUR);
166 }
167 else
168 return -1;
169 }
170
171 #endif /* SIMAGE_LIBSNDFILE_SUPPORT */
172