Project

General

Profile

sndfile.plugin_v3.6jwt.cc

Jim Turner, March 06, 2015 19:39

 
1
/*  Audacious - Cross-platform multimedia player
2
 *  Copyright (C) 2005-2011 Audacious development team
3
 *
4
 *  Based on the xmms_sndfile input plugin:
5
 *  Copyright (C) 2000, 2002 Erik de Castro Lopo
6
 *
7
 *  This program 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 2 of the License, or
10
 *  (at your option) any later version.
11
 *
12
 *  This program 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, write to the Free Software
19
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
 */
21

    
22
#include <math.h>
23
#include <stdlib.h>
24
#include <string.h>
25

    
26
#include <sndfile.h>
27

    
28
#define WANT_VFS_STDIO_COMPAT
29
#include <libaudcore/plugin.h>
30
#include <libaudcore/i18n.h>
31
#include <libaudcore/audstrings.h>
32
#include <libaudcore/runtime.h>
33

    
34
class SndfilePlugin : public InputPlugin
35
{
36
public:
37
    static const char about[];
38
    static const char * const exts[];
39

    
40
    static constexpr PluginInfo info = {
41
        N_("Sndfile Plugin"),
42
        PACKAGE,
43
        about
44
    };
45

    
46
    static constexpr auto iinfo = InputInfo ()
47
        .with_priority (9)  /* low priority fallback (but before ffaudio) */
48
        .with_exts (exts);
49

    
50
    constexpr SndfilePlugin () : InputPlugin (info, iinfo) {}
51

    
52
    bool is_our_file (const char * filename, VFSFile & file);
53
    Tuple read_tuple (const char * filename, VFSFile & file);
54
    bool play (const char * filename, VFSFile & file);
55
};
56

    
57
EXPORT SndfilePlugin aud_plugin_instance;
58

    
59
static SNDFILE * save_sndfile;   /* JWT:NEXT 2 ADDED TO HANDLE INPUT FROM stdin - MUST SAVE FILE DATA SINCE WE CAN'T CLOSE/REOPEN stdin! */
60
static SF_INFO sfinfo;
61

    
62
/* Virtual file access wrappers for libsndfile
63
 */
64
static sf_count_t
65
sf_get_filelen (void *user_data)
66
{
67
    return ((VFSFile *) user_data)->fsize ();
68
}
69

    
70
static sf_count_t
71
sf_vseek (sf_count_t offset, int whence, void *user_data)
72
{
73
    return ((VFSFile *) user_data)->fseek (offset, to_vfs_seek_type (whence));
74
}
75

    
76
static sf_count_t
77
sf_vread (void *ptr, sf_count_t count, void *user_data)
78
{
79
    return ((VFSFile *) user_data)->fread (ptr, 1, count);
80
}
81

    
82
static sf_count_t
83
sf_vwrite (const void *ptr, sf_count_t count, void *user_data)
84
{
85
    return ((VFSFile *) user_data)->fwrite (ptr, 1, count);
86
}
87

    
88
static sf_count_t
89
sf_tell (void *user_data)
90
{
91
    return ((VFSFile *) user_data)->ftell ();
92
}
93

    
94
static SF_VIRTUAL_IO sf_virtual_io =
95
{
96
    sf_get_filelen,
97
    sf_vseek,
98
    sf_vread,
99
    sf_vwrite,
100
    sf_tell
101
};
102

    
103
static void copy_string (SNDFILE * sf, int sf_id, Tuple & tup, Tuple::Field field)
104
{
105
    const char * str = sf_get_string (sf, sf_id);
106
    if (str)
107
        tup.set_str (field, str);
108
}
109

    
110
static void copy_int (SNDFILE * sf, int sf_id, Tuple & tup, Tuple::Field field)
111
{
112
    const char * str = sf_get_string (sf, sf_id);
113
    if (str && atoi (str))
114
        tup.set_int (field, atoi (str));
115
}
116

    
117
Tuple SndfilePlugin::read_tuple (const char * filename, VFSFile & file)
118
{
119
    SNDFILE *sndfile;
120
    /* JWT:MADE PERSISTANT!: SF_INFO sfinfo; */
121
    const char *format, *subformat;
122
    Tuple ti;
123

    
124
    if (strstr(filename, "://-."))   /* JWT:ADDED TO HANDLE INPUT FROM stdin */
125
    {
126
        if (save_sndfile == nullptr)    /* JWT:  ONLY OPEN (stdin) IF THIS IS 1ST CALL. */
127
        {
128
            memset(&sfinfo, 0, sizeof(sfinfo));
129
            sndfile = sf_open_fd(0, SFM_READ, &sfinfo, 0);
130
            AUDDBG("-JWT:SndfilePlugin::read_tuple (FIRST TIME!) sfinfosz=%d=\n", sizeof(sfinfo));
131
        }
132
        else
133
            sndfile = save_sndfile;
134
    }
135
    else
136
    {
137
        sndfile = sf_open_virtual (& sf_virtual_io, SFM_READ, & sfinfo, & file);
138
    }
139
    if (sndfile == nullptr)
140
        return ti;
141

    
142
    if (strstr(filename, "://-."))   /* JWT:ADDED TO HANDLE INPUT FROM stdin */
143
        save_sndfile = sndfile;
144

    
145
    ti.set_filename (filename);
146

    
147
    copy_string (sndfile, SF_STR_TITLE, ti, Tuple::Title);
148
    copy_string (sndfile, SF_STR_ARTIST, ti, Tuple::Artist);
149
    copy_string (sndfile, SF_STR_ALBUM, ti, Tuple::Album);
150
    copy_string (sndfile, SF_STR_COMMENT, ti, Tuple::Comment);
151
    copy_string (sndfile, SF_STR_GENRE, ti, Tuple::Genre);
152
    copy_int (sndfile, SF_STR_DATE, ti, Tuple::Year);
153
    copy_int (sndfile, SF_STR_TRACKNUMBER, ti, Tuple::Track);
154

    
155
    if (!strstr(filename, "://-."))    /* JWT:DON'T EVER CLOSE stdin! */
156
        sf_close (sndfile);
157

    
158
    if (sfinfo.samplerate > 0)
159
        ti.set_int (Tuple::Length, ceil (1000.0 * sfinfo.frames / sfinfo.samplerate));
160

    
161
    switch (sfinfo.format & SF_FORMAT_TYPEMASK)
162
    {
163
        case SF_FORMAT_WAV:
164
        case SF_FORMAT_WAVEX:
165
            format = "Microsoft WAV";
166
            break;
167
        case SF_FORMAT_AIFF:
168
            format = "Apple/SGI AIFF";
169
            break;
170
        case SF_FORMAT_AU:
171
            format = "Sun/NeXT AU";
172
            break;
173
        case SF_FORMAT_RAW:
174
            format = "Raw PCM data";
175
            break;
176
        case SF_FORMAT_PAF:
177
            format = "Ensoniq PARIS";
178
            break;
179
        case SF_FORMAT_SVX:
180
            format = "Amiga IFF / SVX8 / SV16";
181
            break;
182
        case SF_FORMAT_NIST:
183
            format = "Sphere NIST";
184
            break;
185
        case SF_FORMAT_VOC:
186
            format = "Creative VOC";
187
            break;
188
        case SF_FORMAT_IRCAM:
189
            format = "Berkeley/IRCAM/CARL";
190
            break;
191
        case SF_FORMAT_W64:
192
            format = "Sonic Foundry's 64 bit RIFF/WAV";
193
            break;
194
        case SF_FORMAT_MAT4:
195
            format = "Matlab (tm) V4.2 / GNU Octave 2.0";
196
            break;
197
        case SF_FORMAT_MAT5:
198
            format = "Matlab (tm) V5.0 / GNU Octave 2.1";
199
            break;
200
        case SF_FORMAT_PVF:
201
            format = "Portable Voice Format";
202
            break;
203
        case SF_FORMAT_XI:
204
            format = "Fasttracker 2 Extended Instrument";
205
            break;
206
        case SF_FORMAT_HTK:
207
            format = "HMM Tool Kit";
208
            break;
209
        case SF_FORMAT_SDS:
210
            format = "Midi Sample Dump Standard";
211
            break;
212
        case SF_FORMAT_AVR:
213
            format = "Audio Visual Research";
214
            break;
215
        case SF_FORMAT_SD2:
216
            format = "Sound Designer 2";
217
            break;
218
        case SF_FORMAT_FLAC:
219
            format = "Free Lossless Audio Codec";
220
            break;
221
        case SF_FORMAT_CAF:
222
            format = "Core Audio File";
223
            break;
224
        default:
225
            format = "Unknown sndfile";
226
    }
227

    
228
    switch (sfinfo.format & SF_FORMAT_SUBMASK)
229
    {
230
        case SF_FORMAT_PCM_S8:
231
            subformat = "signed 8 bit";
232
            break;
233
        case SF_FORMAT_PCM_16:
234
            subformat = "signed 16 bit";
235
            break;
236
        case SF_FORMAT_PCM_24:
237
            subformat = "signed 24 bit";
238
            break;
239
        case SF_FORMAT_PCM_32:
240
            subformat = "signed 32 bit";
241
            break;
242
        case SF_FORMAT_PCM_U8:
243
            subformat = "unsigned 8 bit";
244
            break;
245
        case SF_FORMAT_FLOAT:
246
            subformat = "32 bit float";
247
            break;
248
        case SF_FORMAT_DOUBLE:
249
            subformat = "64 bit float";
250
            break;
251
        case SF_FORMAT_ULAW:
252
            subformat = "U-Law";
253
            break;
254
        case SF_FORMAT_ALAW:
255
            subformat = "A-Law";
256
            break;
257
        case SF_FORMAT_IMA_ADPCM:
258
            subformat = "IMA ADPCM";
259
            break;
260
        case SF_FORMAT_MS_ADPCM:
261
            subformat = "MS ADPCM";
262
            break;
263
        case SF_FORMAT_GSM610:
264
            subformat = "GSM 6.10";
265
            break;
266
        case SF_FORMAT_VOX_ADPCM:
267
            subformat = "Oki Dialogic ADPCM";
268
            break;
269
        case SF_FORMAT_G721_32:
270
            subformat = "32kbs G721 ADPCM";
271
            break;
272
        case SF_FORMAT_G723_24:
273
            subformat = "24kbs G723 ADPCM";
274
            break;
275
        case SF_FORMAT_G723_40:
276
            subformat = "40kbs G723 ADPCM";
277
            break;
278
        case SF_FORMAT_DWVW_12:
279
            subformat = "12 bit Delta Width Variable Word";
280
            break;
281
        case SF_FORMAT_DWVW_16:
282
            subformat = "16 bit Delta Width Variable Word";
283
            break;
284
        case SF_FORMAT_DWVW_24:
285
            subformat = "24 bit Delta Width Variable Word";
286
            break;
287
        case SF_FORMAT_DWVW_N:
288
            subformat = "N bit Delta Width Variable Word";
289
            break;
290
        case SF_FORMAT_DPCM_8:
291
            subformat = "8 bit differential PCM";
292
            break;
293
        case SF_FORMAT_DPCM_16:
294
            subformat = "16 bit differential PCM";
295
            break;
296
        default:
297
            subformat = nullptr;
298
    }
299

    
300
    if (subformat != nullptr)
301
        ti.set_format (str_printf ("%s (%s)", format, subformat),
302
            sfinfo.channels, sfinfo.samplerate, 0);
303
    else
304
        ti.set_format (format, sfinfo.channels, sfinfo.samplerate, 0);
305

    
306
    return ti;
307
}
308

    
309
bool SndfilePlugin::play (const char * filename, VFSFile & file)
310
{
311
    SNDFILE *sndfile = NULL;
312
    /* JWT:MADE PERSISTANT!: SF_INFO sfinfo; */
313
    if (strstr(filename, "://-."))    /* JWT:ADDED TO HANDLE INPUT FROM stdin */
314
    {
315
        if (save_sndfile == nullptr)    /* JWT:  ONLY OPEN (stdin) IF THIS IS 1ST CALL. */
316
        {
317
            memset(&sfinfo, 0, sizeof(sfinfo));
318
            sndfile = sf_open_fd(0, SFM_READ, &sfinfo, 0);
319
        }
320
        else
321
        {
322
            sndfile = save_sndfile;
323
        }
324
    }
325
    else
326
    {
327
        sndfile = sf_open_virtual (& sf_virtual_io, SFM_READ, & sfinfo, & file);
328
    }
329
    if (sndfile == nullptr)
330
        return false;
331

    
332
    if (strstr(filename, "://-."))   /* JWT:ADDED TO HANDLE INPUT FROM stdin */
333
        save_sndfile = sndfile;
334
    open_audio (FMT_FLOAT, sfinfo.samplerate, sfinfo.channels);
335

    
336
    Index<float> buffer;
337
    buffer.resize (sfinfo.channels * (sfinfo.samplerate / 50));
338

    
339
    while (! check_stop ())
340
    {
341
        int seek_value = check_seek ();
342
        if (seek_value != -1)
343
            sf_seek (sndfile, (int64_t) seek_value * sfinfo.samplerate / 1000, SEEK_SET);
344

    
345
        int samples = sf_read_float (sndfile, buffer.begin (), buffer.len ());
346
        if (! samples)
347
            break;
348

    
349
        write_audio (buffer.begin (), sizeof (float) * samples);
350
    }
351

    
352
    if (!strstr(filename, "://-."))   /* JWT:DON'T EVER CLOSE stdin! */
353
        sf_close (sndfile);
354

    
355
    return true;
356
}
357

    
358
bool SndfilePlugin::is_our_file (const char * filename, VFSFile & file)
359
{
360
    if (strstr(filename, "://-."))   /* JWT:ADDED TO HANDLE INPUT FROM stdin */
361
        return true;
362
                
363
    SNDFILE *tmp_sndfile;
364
    SF_INFO tmp_sfinfo;
365

    
366
    /* Have to open the file to see if libsndfile can handle it. */
367
    tmp_sndfile = sf_open_virtual (&sf_virtual_io, SFM_READ, &tmp_sfinfo, &file);
368

    
369
    if (!tmp_sndfile)
370
        return false;
371

    
372
    /* It can so close file and return true. */
373
    sf_close (tmp_sndfile);
374
    tmp_sndfile = nullptr;
375

    
376
    return true;
377
}
378

    
379
const char SndfilePlugin::about[] =
380
 N_("Based on the xmms_sndfile plugin:\n"
381
    "Copyright (C) 2000, 2002 Erik de Castro Lopo\n\n"
382
    "Adapted for Audacious by Tony Vroon <chainsaw@gentoo.org>\n\n"
383
    "This program is free software; you can redistribute it and/or "
384
    "modify it under the terms of the GNU General Public License "
385
    "as published by the Free Software Foundation; either version 2 "
386
    "of the License, or (at your option) any later version.\n\n"
387
    "This program is distributed in the hope that it will be useful, "
388
    "but WITHOUT ANY WARRANTY; without even the implied warranty of "
389
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the "
390
    "GNU General Public License for more details.\n\n"
391
    "You should have received a copy of the GNU General Public License "
392
    "along with this program; if not, write to the Free Software "
393
    "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.");
394

    
395
const char * const SndfilePlugin::exts[] = { "aiff", "au", "raw", "wav", nullptr };