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