2009-05-26 00:05:28 +02:00
|
|
|
/***
|
|
|
|
|
This file is part of PulseAudio.
|
|
|
|
|
|
|
|
|
|
Copyright 2009 Lennart Poettering
|
|
|
|
|
|
|
|
|
|
PulseAudio is free software; you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU Lesser General Public License as published
|
|
|
|
|
by the Free Software Foundation; either version 2.1 of the License,
|
|
|
|
|
or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
PulseAudio is distributed in the hope that it will be useful, but
|
|
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
|
|
|
along with PulseAudio; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
|
|
|
USA.
|
|
|
|
|
***/
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Shared between pacat/parec/paplay and the server */
|
|
|
|
|
|
|
|
|
|
#include <pulse/xmalloc.h>
|
|
|
|
|
#include <pulse/utf8.h>
|
|
|
|
|
|
|
|
|
|
#include <pulsecore/macro.h>
|
|
|
|
|
|
|
|
|
|
#include "sndfile-util.h"
|
|
|
|
|
|
|
|
|
|
int pa_sndfile_read_sample_spec(SNDFILE *sf, pa_sample_spec *ss) {
|
|
|
|
|
SF_INFO sfi;
|
|
|
|
|
|
|
|
|
|
pa_assert(sf);
|
|
|
|
|
pa_assert(ss);
|
|
|
|
|
|
|
|
|
|
pa_zero(sfi);
|
|
|
|
|
pa_assert_se(sf_command(sf, SFC_GET_CURRENT_SF_INFO, &sfi, sizeof(sfi)) == 0);
|
|
|
|
|
|
|
|
|
|
switch (sfi.format & SF_FORMAT_SUBMASK) {
|
|
|
|
|
|
|
|
|
|
case SF_FORMAT_PCM_16:
|
|
|
|
|
case SF_FORMAT_PCM_U8:
|
|
|
|
|
case SF_FORMAT_PCM_S8:
|
|
|
|
|
ss->format = PA_SAMPLE_S16NE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SF_FORMAT_PCM_24:
|
2011-02-08 11:24:08 +01:00
|
|
|
ss->format = PA_SAMPLE_S24NE;
|
2011-03-02 12:41:26 +01:00
|
|
|
break;
|
2011-02-08 11:24:08 +01:00
|
|
|
|
2009-05-26 00:05:28 +02:00
|
|
|
case SF_FORMAT_PCM_32:
|
|
|
|
|
ss->format = PA_SAMPLE_S32NE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SF_FORMAT_ULAW:
|
|
|
|
|
ss->format = PA_SAMPLE_ULAW;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SF_FORMAT_ALAW:
|
|
|
|
|
ss->format = PA_SAMPLE_ALAW;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SF_FORMAT_FLOAT:
|
|
|
|
|
case SF_FORMAT_DOUBLE:
|
|
|
|
|
default:
|
|
|
|
|
ss->format = PA_SAMPLE_FLOAT32NE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ss->rate = (uint32_t) sfi.samplerate;
|
|
|
|
|
ss->channels = (uint8_t) sfi.channels;
|
|
|
|
|
|
|
|
|
|
if (!pa_sample_spec_valid(ss))
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int pa_sndfile_write_sample_spec(SF_INFO *sfi, pa_sample_spec *ss) {
|
|
|
|
|
pa_assert(sfi);
|
|
|
|
|
pa_assert(ss);
|
|
|
|
|
|
|
|
|
|
sfi->samplerate = (int) ss->rate;
|
|
|
|
|
sfi->channels = (int) ss->channels;
|
|
|
|
|
|
|
|
|
|
if (pa_sample_format_is_le(ss->format) > 0)
|
|
|
|
|
sfi->format = SF_ENDIAN_LITTLE;
|
|
|
|
|
else if (pa_sample_format_is_be(ss->format) > 0)
|
|
|
|
|
sfi->format = SF_ENDIAN_BIG;
|
|
|
|
|
|
|
|
|
|
switch (ss->format) {
|
|
|
|
|
|
|
|
|
|
case PA_SAMPLE_U8:
|
|
|
|
|
ss->format = PA_SAMPLE_S16NE;
|
|
|
|
|
sfi->format = SF_FORMAT_PCM_U8;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PA_SAMPLE_S16LE:
|
|
|
|
|
case PA_SAMPLE_S16BE:
|
|
|
|
|
ss->format = PA_SAMPLE_S16NE;
|
|
|
|
|
sfi->format |= SF_FORMAT_PCM_16;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PA_SAMPLE_S24LE:
|
|
|
|
|
case PA_SAMPLE_S24BE:
|
2011-03-02 12:41:26 +01:00
|
|
|
ss->format = PA_SAMPLE_S24NE;
|
|
|
|
|
sfi->format |= SF_FORMAT_PCM_24;
|
|
|
|
|
break;
|
2011-02-08 11:24:08 +01:00
|
|
|
|
2009-05-26 00:05:28 +02:00
|
|
|
case PA_SAMPLE_S24_32LE:
|
|
|
|
|
case PA_SAMPLE_S24_32BE:
|
2011-02-08 11:24:08 +01:00
|
|
|
ss->format = PA_SAMPLE_S24_32NE;
|
|
|
|
|
sfi->format |= SF_FORMAT_PCM_32;
|
2009-05-26 00:05:28 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PA_SAMPLE_S32LE:
|
2009-06-23 18:54:17 +02:00
|
|
|
case PA_SAMPLE_S32BE:
|
2009-05-26 00:05:28 +02:00
|
|
|
ss->format = PA_SAMPLE_S32NE;
|
|
|
|
|
sfi->format |= SF_FORMAT_PCM_32;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PA_SAMPLE_ULAW:
|
|
|
|
|
sfi->format = SF_FORMAT_ULAW;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PA_SAMPLE_ALAW:
|
|
|
|
|
sfi->format = SF_FORMAT_ALAW;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PA_SAMPLE_FLOAT32LE:
|
|
|
|
|
case PA_SAMPLE_FLOAT32BE:
|
|
|
|
|
default:
|
|
|
|
|
ss->format = PA_SAMPLE_FLOAT32NE;
|
|
|
|
|
sfi->format |= SF_FORMAT_FLOAT;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!pa_sample_spec_valid(ss))
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int pa_sndfile_read_channel_map(SNDFILE *sf, pa_channel_map *cm) {
|
|
|
|
|
|
|
|
|
|
static const pa_channel_position_t table[] = {
|
|
|
|
|
[SF_CHANNEL_MAP_MONO] = PA_CHANNEL_POSITION_MONO,
|
|
|
|
|
[SF_CHANNEL_MAP_LEFT] = PA_CHANNEL_POSITION_FRONT_LEFT, /* libsndfile distuingishes left und front-left, which we don't */
|
|
|
|
|
[SF_CHANNEL_MAP_RIGHT] = PA_CHANNEL_POSITION_FRONT_RIGHT,
|
|
|
|
|
[SF_CHANNEL_MAP_CENTER] = PA_CHANNEL_POSITION_FRONT_CENTER,
|
|
|
|
|
[SF_CHANNEL_MAP_FRONT_LEFT] = PA_CHANNEL_POSITION_FRONT_LEFT,
|
|
|
|
|
[SF_CHANNEL_MAP_FRONT_RIGHT] = PA_CHANNEL_POSITION_FRONT_RIGHT,
|
|
|
|
|
[SF_CHANNEL_MAP_FRONT_CENTER] = PA_CHANNEL_POSITION_FRONT_CENTER,
|
|
|
|
|
[SF_CHANNEL_MAP_REAR_CENTER] = PA_CHANNEL_POSITION_REAR_CENTER,
|
|
|
|
|
[SF_CHANNEL_MAP_REAR_LEFT] = PA_CHANNEL_POSITION_REAR_LEFT,
|
|
|
|
|
[SF_CHANNEL_MAP_REAR_RIGHT] = PA_CHANNEL_POSITION_REAR_RIGHT,
|
|
|
|
|
[SF_CHANNEL_MAP_LFE] = PA_CHANNEL_POSITION_LFE,
|
|
|
|
|
[SF_CHANNEL_MAP_FRONT_LEFT_OF_CENTER] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
|
|
|
|
|
[SF_CHANNEL_MAP_FRONT_RIGHT_OF_CENTER] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
|
|
|
|
|
[SF_CHANNEL_MAP_SIDE_LEFT] = PA_CHANNEL_POSITION_SIDE_LEFT,
|
|
|
|
|
[SF_CHANNEL_MAP_SIDE_RIGHT] = PA_CHANNEL_POSITION_SIDE_RIGHT,
|
|
|
|
|
[SF_CHANNEL_MAP_TOP_CENTER] = PA_CHANNEL_POSITION_TOP_CENTER,
|
|
|
|
|
[SF_CHANNEL_MAP_TOP_FRONT_LEFT] = PA_CHANNEL_POSITION_TOP_FRONT_LEFT,
|
|
|
|
|
[SF_CHANNEL_MAP_TOP_FRONT_RIGHT] = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT,
|
|
|
|
|
[SF_CHANNEL_MAP_TOP_FRONT_CENTER] = PA_CHANNEL_POSITION_TOP_FRONT_CENTER,
|
|
|
|
|
[SF_CHANNEL_MAP_TOP_REAR_LEFT] = PA_CHANNEL_POSITION_TOP_REAR_LEFT,
|
|
|
|
|
[SF_CHANNEL_MAP_TOP_REAR_RIGHT] = PA_CHANNEL_POSITION_TOP_REAR_RIGHT,
|
|
|
|
|
[SF_CHANNEL_MAP_TOP_REAR_CENTER] = PA_CHANNEL_POSITION_TOP_REAR_CENTER
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
SF_INFO sfi;
|
|
|
|
|
int *channels;
|
|
|
|
|
unsigned c;
|
|
|
|
|
|
|
|
|
|
pa_assert(sf);
|
|
|
|
|
pa_assert(cm);
|
|
|
|
|
|
|
|
|
|
pa_zero(sfi);
|
|
|
|
|
pa_assert_se(sf_command(sf, SFC_GET_CURRENT_SF_INFO, &sfi, sizeof(sfi)) == 0);
|
|
|
|
|
|
|
|
|
|
channels = pa_xnew(int, sfi.channels);
|
|
|
|
|
if (!sf_command(sf, SFC_GET_CHANNEL_MAP_INFO,
|
|
|
|
|
channels, sizeof(channels[0]) * sfi.channels)) {
|
|
|
|
|
|
|
|
|
|
pa_xfree(channels);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cm->channels = (uint8_t) sfi.channels;
|
|
|
|
|
for (c = 0; c < cm->channels; c++) {
|
|
|
|
|
if (channels[c] <= SF_CHANNEL_MAP_INVALID ||
|
|
|
|
|
(unsigned) channels[c] >= PA_ELEMENTSOF(table)) {
|
|
|
|
|
pa_xfree(channels);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cm->map[c] = table[channels[c]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pa_xfree(channels);
|
|
|
|
|
|
|
|
|
|
if (!pa_channel_map_valid(cm))
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int pa_sndfile_write_channel_map(SNDFILE *sf, pa_channel_map *cm) {
|
|
|
|
|
static const int table[PA_CHANNEL_POSITION_MAX] = {
|
|
|
|
|
[PA_CHANNEL_POSITION_MONO] = SF_CHANNEL_MAP_MONO,
|
|
|
|
|
|
|
|
|
|
[PA_CHANNEL_POSITION_FRONT_LEFT] = SF_CHANNEL_MAP_FRONT_LEFT,
|
|
|
|
|
[PA_CHANNEL_POSITION_FRONT_RIGHT] = SF_CHANNEL_MAP_FRONT_RIGHT,
|
|
|
|
|
[PA_CHANNEL_POSITION_FRONT_CENTER] = SF_CHANNEL_MAP_FRONT_CENTER,
|
|
|
|
|
|
|
|
|
|
[PA_CHANNEL_POSITION_REAR_CENTER] = SF_CHANNEL_MAP_REAR_CENTER,
|
|
|
|
|
[PA_CHANNEL_POSITION_REAR_LEFT] = SF_CHANNEL_MAP_REAR_LEFT,
|
|
|
|
|
[PA_CHANNEL_POSITION_REAR_RIGHT] = SF_CHANNEL_MAP_REAR_RIGHT,
|
|
|
|
|
|
|
|
|
|
[PA_CHANNEL_POSITION_LFE] = SF_CHANNEL_MAP_LFE,
|
|
|
|
|
|
|
|
|
|
[PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = SF_CHANNEL_MAP_FRONT_LEFT_OF_CENTER,
|
|
|
|
|
[PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = SF_CHANNEL_MAP_FRONT_RIGHT_OF_CENTER,
|
|
|
|
|
|
|
|
|
|
[PA_CHANNEL_POSITION_SIDE_LEFT] = SF_CHANNEL_MAP_SIDE_LEFT,
|
|
|
|
|
[PA_CHANNEL_POSITION_SIDE_RIGHT] = SF_CHANNEL_MAP_SIDE_RIGHT,
|
|
|
|
|
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX0] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX1] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX2] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX3] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX4] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX5] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX6] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX7] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX8] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX9] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX10] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX11] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX12] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX13] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX14] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX15] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX16] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX17] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX18] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX19] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX20] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX21] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX22] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX23] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX24] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX25] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX26] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX27] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX28] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX29] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX30] = -1,
|
|
|
|
|
[PA_CHANNEL_POSITION_AUX31] = -1,
|
|
|
|
|
|
|
|
|
|
[PA_CHANNEL_POSITION_TOP_CENTER] = SF_CHANNEL_MAP_TOP_CENTER,
|
|
|
|
|
|
|
|
|
|
[PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = SF_CHANNEL_MAP_TOP_FRONT_LEFT,
|
|
|
|
|
[PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = SF_CHANNEL_MAP_TOP_FRONT_RIGHT,
|
|
|
|
|
[PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = SF_CHANNEL_MAP_TOP_FRONT_CENTER ,
|
|
|
|
|
|
|
|
|
|
[PA_CHANNEL_POSITION_TOP_REAR_LEFT] = SF_CHANNEL_MAP_TOP_REAR_LEFT,
|
|
|
|
|
[PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = SF_CHANNEL_MAP_TOP_REAR_RIGHT,
|
|
|
|
|
[PA_CHANNEL_POSITION_TOP_REAR_CENTER] = SF_CHANNEL_MAP_TOP_REAR_CENTER,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int *channels;
|
|
|
|
|
unsigned c;
|
|
|
|
|
|
|
|
|
|
pa_assert(sf);
|
|
|
|
|
pa_assert(cm);
|
|
|
|
|
|
|
|
|
|
/* Suppress channel mapping for the obvious cases */
|
|
|
|
|
if (cm->channels == 1 && cm->map[0] == PA_CHANNEL_POSITION_MONO)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (cm->channels == 2 &&
|
|
|
|
|
cm->map[0] == PA_CHANNEL_POSITION_FRONT_LEFT &&
|
|
|
|
|
cm->map[1] == PA_CHANNEL_POSITION_FRONT_RIGHT)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
channels = pa_xnew(int, cm->channels);
|
|
|
|
|
for (c = 0; c < cm->channels; c++) {
|
|
|
|
|
|
|
|
|
|
if (cm->map[c] < 0 ||
|
|
|
|
|
cm->map[c] >= PA_CHANNEL_POSITION_MAX ||
|
|
|
|
|
table[cm->map[c]] < 0) {
|
|
|
|
|
pa_xfree(channels);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
channels[c] = table[cm->map[c]];
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-02 12:41:26 +01:00
|
|
|
if (!sf_command(sf, SFC_SET_CHANNEL_MAP_INFO, channels, sizeof(channels[0]) * cm->channels)) {
|
2009-05-26 00:05:28 +02:00
|
|
|
pa_xfree(channels);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pa_xfree(channels);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pa_sndfile_init_proplist(SNDFILE *sf, pa_proplist *p) {
|
|
|
|
|
|
|
|
|
|
static const char* table[] = {
|
|
|
|
|
[SF_STR_TITLE] = PA_PROP_MEDIA_TITLE,
|
|
|
|
|
[SF_STR_COPYRIGHT] = PA_PROP_MEDIA_COPYRIGHT,
|
|
|
|
|
[SF_STR_SOFTWARE] = PA_PROP_MEDIA_SOFTWARE,
|
|
|
|
|
[SF_STR_ARTIST] = PA_PROP_MEDIA_ARTIST,
|
|
|
|
|
[SF_STR_COMMENT] = "media.comment",
|
|
|
|
|
[SF_STR_DATE] = "media.date"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
SF_INFO sfi;
|
|
|
|
|
SF_FORMAT_INFO fi;
|
|
|
|
|
unsigned c;
|
|
|
|
|
|
|
|
|
|
pa_assert(sf);
|
|
|
|
|
pa_assert(p);
|
|
|
|
|
|
|
|
|
|
for (c = 0; c < PA_ELEMENTSOF(table); c++) {
|
|
|
|
|
const char *s;
|
|
|
|
|
char *t;
|
|
|
|
|
|
|
|
|
|
if (!table[c])
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (!(s = sf_get_string(sf, c)))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
t = pa_utf8_filter(s);
|
|
|
|
|
pa_proplist_sets(p, table[c], t);
|
|
|
|
|
pa_xfree(t);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pa_zero(sfi);
|
|
|
|
|
pa_assert_se(sf_command(sf, SFC_GET_CURRENT_SF_INFO, &sfi, sizeof(sfi)) == 0);
|
|
|
|
|
|
|
|
|
|
pa_zero(fi);
|
|
|
|
|
fi.format = sfi.format;
|
|
|
|
|
if (sf_command(sf, SFC_GET_FORMAT_INFO, &fi, sizeof(fi)) == 0 && fi.name) {
|
|
|
|
|
char *t;
|
|
|
|
|
|
|
|
|
|
t = pa_utf8_filter(fi.name);
|
|
|
|
|
pa_proplist_sets(p, "media.format", t);
|
|
|
|
|
pa_xfree(t);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pa_sndfile_readf_t pa_sndfile_readf_function(const pa_sample_spec *ss) {
|
|
|
|
|
pa_assert(ss);
|
|
|
|
|
|
|
|
|
|
switch (ss->format) {
|
|
|
|
|
case PA_SAMPLE_S16NE:
|
|
|
|
|
return (pa_sndfile_readf_t) sf_readf_short;
|
|
|
|
|
|
|
|
|
|
case PA_SAMPLE_S32NE:
|
2011-02-08 11:24:08 +01:00
|
|
|
case PA_SAMPLE_S24_32NE:
|
2009-05-26 00:05:28 +02:00
|
|
|
return (pa_sndfile_readf_t) sf_readf_int;
|
|
|
|
|
|
|
|
|
|
case PA_SAMPLE_FLOAT32NE:
|
|
|
|
|
return (pa_sndfile_readf_t) sf_readf_float;
|
|
|
|
|
|
|
|
|
|
case PA_SAMPLE_ULAW:
|
|
|
|
|
case PA_SAMPLE_ALAW:
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
pa_assert_not_reached();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pa_sndfile_writef_t pa_sndfile_writef_function(const pa_sample_spec *ss) {
|
|
|
|
|
pa_assert(ss);
|
|
|
|
|
|
|
|
|
|
switch (ss->format) {
|
|
|
|
|
case PA_SAMPLE_S16NE:
|
|
|
|
|
return (pa_sndfile_writef_t) sf_writef_short;
|
|
|
|
|
|
|
|
|
|
case PA_SAMPLE_S32NE:
|
2011-02-08 11:24:08 +01:00
|
|
|
case PA_SAMPLE_S24_32NE:
|
2009-05-26 00:05:28 +02:00
|
|
|
return (pa_sndfile_writef_t) sf_writef_int;
|
|
|
|
|
|
|
|
|
|
case PA_SAMPLE_FLOAT32NE:
|
|
|
|
|
return (pa_sndfile_writef_t) sf_writef_float;
|
|
|
|
|
|
|
|
|
|
case PA_SAMPLE_ULAW:
|
|
|
|
|
case PA_SAMPLE_ALAW:
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
pa_assert_not_reached();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int pa_sndfile_format_from_string(const char *name) {
|
|
|
|
|
int i, count = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!name[0])
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
pa_assert_se(sf_command(NULL, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof(int)) == 0);
|
|
|
|
|
|
|
|
|
|
/* First try to match via full type string */
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
|
SF_FORMAT_INFO fi;
|
|
|
|
|
pa_zero(fi);
|
|
|
|
|
fi.format = i;
|
|
|
|
|
|
|
|
|
|
pa_assert_se(sf_command(NULL, SFC_GET_FORMAT_MAJOR, &fi, sizeof(fi)) == 0);
|
|
|
|
|
|
|
|
|
|
if (strcasecmp(name, fi.name) == 0)
|
2010-12-14 18:08:14 +01:00
|
|
|
return fi.format;
|
2009-05-26 00:05:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Then, try to match via the full extension */
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
|
SF_FORMAT_INFO fi;
|
|
|
|
|
pa_zero(fi);
|
|
|
|
|
fi.format = i;
|
|
|
|
|
|
|
|
|
|
pa_assert_se(sf_command(NULL, SFC_GET_FORMAT_MAJOR, &fi, sizeof(fi)) == 0);
|
|
|
|
|
|
|
|
|
|
if (strcasecmp(name, fi.extension) == 0)
|
2010-12-14 18:08:14 +01:00
|
|
|
return fi.format;
|
2009-05-26 00:05:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Then, try to match via the start of the type string */
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
|
SF_FORMAT_INFO fi;
|
|
|
|
|
pa_zero(fi);
|
|
|
|
|
fi.format = i;
|
|
|
|
|
|
|
|
|
|
pa_assert_se(sf_command(NULL, SFC_GET_FORMAT_MAJOR, &fi, sizeof(fi)) == 0);
|
|
|
|
|
|
2011-06-27 01:19:07 +02:00
|
|
|
if (strncasecmp(name, fi.name, strlen(name)) == 0)
|
2010-12-14 18:08:14 +01:00
|
|
|
return fi.format;
|
2009-05-26 00:05:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pa_sndfile_dump_formats(void) {
|
|
|
|
|
int i, count = 0;
|
|
|
|
|
|
|
|
|
|
pa_assert_se(sf_command(NULL, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof(int)) == 0);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
|
SF_FORMAT_INFO fi;
|
|
|
|
|
pa_zero(fi);
|
|
|
|
|
fi.format = i;
|
|
|
|
|
|
|
|
|
|
pa_assert_se(sf_command(NULL, SFC_GET_FORMAT_MAJOR, &fi, sizeof(fi)) == 0);
|
|
|
|
|
printf("%s\t%s\n", fi.extension, fi.name);
|
|
|
|
|
}
|
|
|
|
|
}
|