Initial git import
[sxemacs] / src / media / media-sox.c
1 /* media-sox.c - analyse audio files or streams via sox
2
3    Copyright (C) 2006 Sebastian Freundt
4
5 This file is part of SXEmacs
6
7 SXEmacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 SXEmacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
19
20
21 /* Synched up with: Not in FSF. */
22
23 #include <config.h>
24 #include "lisp.h"
25
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <stdio.h>
29 #include <errno.h>
30 #include <string.h>
31
32 #include "media-sox.h"
33
34 #define MYSELF MDRIVER_SOX
35
36 Lisp_Object Qsox;
37
38 #define __SOX_DEBUG__(args...)          fprintf(stderr, "SOX " args)
39 #ifndef SOX_DEBUG_FLAG
40 #define SOX_DEBUG(args...)
41 #else
42 #define SOX_DEBUG(args...)              __SOX_DEBUG__(args)
43 #endif
44 #define SOX_DEBUG_S(args...)            SOX_DEBUG("[stream]: " args)
45 #define SOX_CRITICAL(args...)           __SOX_DEBUG__("CRITICAL: " args)
46
47 \f
48 DECLARE_MEDIA_DRIVER_OPEN_METH(media_sox);
49 DECLARE_MEDIA_DRIVER_CLOSE_METH(media_sox);
50 DECLARE_MEDIA_DRIVER_READ_METH(media_sox);
51 DECLARE_MEDIA_DRIVER_REWIND_METH(media_sox);
52
53 DEFINE_MEDIA_DRIVER_CUSTOM(media_sox,
54                            media_sox_open, media_sox_close,
55                            NULL, NULL,
56                            media_sox_read, NULL,
57                            media_sox_rewind, NULL);
58
59 \f
60 /* called from util.c::st_fail() */
61 void cleanup(void) 
62 {
63 }
64
65 \f
66 static ms_driver_data_t
67 media_sox_open(Lisp_Media_Stream *ms)
68 {
69         media_substream *mss;
70         mtype_audio_properties *mtap;
71         char *name = NULL;
72         /* libsndfile stuff */
73         sxe_sox_t ft = NULL;
74         sxe_sox_signalinfo_t *stinfo = NULL;
75
76         /* initialise */
77         switch (media_stream_kind(ms)) {
78         case MKIND_FILE: {
79                 mkind_file_properties *mkfp = NULL;
80                 const char *file;
81                 int file_len = 0;
82
83                 /* open the file */
84                 mkfp = media_stream_kind_properties(ms).fprops;
85                 TO_EXTERNAL_FORMAT(LISP_STRING, mkfp->filename,
86                                    ALLOCA, (file, file_len), Qnil);
87 #if defined HAVE_SOX_OPEN_READ_3ARGS
88                 ft = sxe_sox_open_read(file, NULL, NULL);
89 #elif defined HAVE_SOX_OPEN_READ_4ARGS
90                 ft = sxe_sox_open_read(file, NULL, NULL, NULL);
91 #else
92 # error You shouldnt be here.  Wake up before you try to compile me.
93 #endif
94                 break;
95         }
96         case MKIND_STRING: {
97                 /* not yet handable */
98                 break;
99         }
100         default:
101                 break;
102         }
103
104         if (!ft) {
105                 media_stream_set_meths(ms, NULL);
106                 media_stream_driver(ms) = MDRIVER_UNKNOWN;
107                 return NULL;
108         }
109
110         /* retrieve the signal information */
111 #if defined HAVE_STRUCT_SOX_FORMAT
112         stinfo = &ft->signal;
113 #elif defined MEMBER_STRUCT_ST_SOUNDSTREAM_SIGNAL
114         stinfo = &ft->signal;
115 #elif defined MEMBER_STRUCT_ST_SOUNDSTREAM_INFO
116         stinfo = &ft->info;
117 #else
118 #  error "What's the matter with you?! How did you reach this?"
119 #endif
120
121         /* create a substream */
122         mss = make_media_substream_append(ms);
123         media_substream_type(mss) = MTYPE_AUDIO;
124         mtap = xnew_and_zero(mtype_audio_properties);
125
126         mtap->channels = stinfo->channels;
127         mtap->samplerate = stinfo->rate;
128
129         /* try to find a read function */
130 #if defined HAVE_SOX_SIGNALINFO_T_PRECISION
131         mtap->samplewidth = stinfo->precision;
132         mtap->framesize = mtap->channels * (stinfo->precision / 8);
133 #else
134         switch (stinfo->size) {
135         case SXE_SIZE_8BIT:
136                 mtap->samplewidth = 8;
137                 mtap->framesize = mtap->channels;
138                 break;
139         case SXE_SIZE_16BIT:
140                 mtap->samplewidth = 16;
141                 mtap->framesize = mtap->channels * 2;
142                 break;
143         case SXE_SIZE_24BIT:
144                 mtap->samplewidth = 24;
145                 mtap->framesize = mtap->channels * 3;
146                 break;
147         case SXE_SIZE_32BIT:
148                 mtap->samplewidth = 32;
149                 mtap->framesize = mtap->channels * 4;
150                 break;
151         case SXE_SIZE_64BIT:
152                 mtap->samplewidth = 64;
153                 mtap->framesize = mtap->channels * 8;
154                 break;
155         default:
156                 mtap->samplewidth = 32;
157                 mtap->framesize = mtap->channels * 4;
158                 break;
159         }
160 #endif
161         /* since SoX internally uses S32, we bang from S32 */
162         mtap->msf = sxe_msf_S32;
163 #if 0
164         mtap->samplewidth = 8 * sizeof(float);
165         mtap->framesize = mtap->channels * sizeof(float);
166 #endif
167
168         mtap->name = name;
169         mtap->endianness = 0;
170
171         /* now assign */
172         media_substream_type_properties(mss).aprops = mtap;
173         media_stream_set_meths(ms, media_sox);
174
175         /* keep the sox handle */
176         media_stream_data(ms) = ft;
177         media_substream_data(mss) = ft;
178
179         /* set me as driver indicator */
180         media_stream_driver(ms) = MYSELF;
181
182         return ft;
183 }
184
185 static void
186 media_sox_close(ms_driver_data_t arg)
187 {
188         sxe_sox_t ft = arg;
189         sxe_sox_close(ft);
190
191         SOX_DEBUG("closing SoX handle: 0x%x\n",
192                   (unsigned int)ft);
193
194         return;
195 }
196
197 \f
198 static size_t
199 media_sox_read(media_substream *mss, void *outbuf, size_t length)
200 {
201 /* read at most `length' frames into `outbuf' */
202         /* stream stuff */
203         Lisp_Media_Stream *ms = mss->up;
204         mtype_audio_properties *mtap;
205         /* libst stuff */
206         sxe_sox_t ft;
207         sxe_sox_ssize_t samples;
208         sxe_sox_sample_t *bptr;
209         uint16_t framesize;
210         media_sample_format_t *fmt;
211
212         /* check the integrity of the media stream */
213         if (media_stream_driver(ms) != MYSELF)
214                 return 0;
215         if (media_substream_type(mss) != MTYPE_AUDIO)
216                 return 0;
217
218         /* fetch the context and our audio props */
219         if (!(ft = media_stream_data(ms)))
220                 return 0;
221         if (!(mtap = media_substream_type_properties(mss).aprops))
222                 return 0;
223
224         framesize = mtap->framesize;
225         fmt = mtap->msf;
226
227         bptr = (sxe_sox_sample_t*)outbuf;
228         samples = sxe_sox_read(ft, bptr, mtap->channels*length);
229
230         SOX_DEBUG_S("read %d samples\n", samples);
231
232         if (samples < 0)
233                 return 0;
234
235         /* always convert to internal format */
236         MEDIA_SAMPLE_FORMAT_UPSAMPLE(fmt)(outbuf, outbuf, samples);
237
238         /* return number of frames */
239         return samples/mtap->channels;
240 }
241
242 static void
243 media_sox_rewind(media_substream *mss)
244 {
245 /* rewind the stream to the first frame */
246         Lisp_Media_Stream *ms = mss->up;
247         /* libst stuff */
248         sxe_sox_t ft;
249
250         /* check the integrity of the media stream */
251         if (media_stream_driver(ms) != MYSELF)
252                 return;
253         if (media_substream_type(mss) != MTYPE_AUDIO)
254                 return;
255
256         /* fetch the SNDFILE context and our audio props */
257         if (!(ft = media_stream_data(ms)))
258                 return;
259
260         SOX_DEBUG_S("rewind stream 0x%x\n", (unsigned int)ft);
261         sxe_sox_seek(ft, 0, SEEK_SET);
262 }
263
264 #undef MYSELF