Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 166 lines (152 sloc) 5.717 kb
#include "libsndfilesrc.h"
#include "win32util.h"
static
uint32_t convert_chanmap(uint32_t value)
{
switch (value) {
case SF_CHANNEL_MAP_MONO:
case SF_CHANNEL_MAP_LEFT: case SF_CHANNEL_MAP_FRONT_LEFT:
return 1;
case SF_CHANNEL_MAP_RIGHT: case SF_CHANNEL_MAP_FRONT_RIGHT:
return 2;
case SF_CHANNEL_MAP_CENTER: case SF_CHANNEL_MAP_FRONT_CENTER:
return 3;
case SF_CHANNEL_MAP_LFE: return 4;
case SF_CHANNEL_MAP_REAR_LEFT: return 5;
case SF_CHANNEL_MAP_REAR_RIGHT: return 6;
case SF_CHANNEL_MAP_FRONT_LEFT_OF_CENTER: return 7;
case SF_CHANNEL_MAP_FRONT_RIGHT_OF_CENTER: return 8;
case SF_CHANNEL_MAP_REAR_CENTER: return 9;
case SF_CHANNEL_MAP_SIDE_LEFT: return 10;
case SF_CHANNEL_MAP_SIDE_RIGHT: return 11;
case SF_CHANNEL_MAP_TOP_CENTER: return 12;
case SF_CHANNEL_MAP_TOP_FRONT_LEFT: return 13;
case SF_CHANNEL_MAP_TOP_FRONT_CENTER: return 15;
case SF_CHANNEL_MAP_TOP_FRONT_RIGHT: return 15;
case SF_CHANNEL_MAP_TOP_REAR_LEFT: return 16;
case SF_CHANNEL_MAP_TOP_REAR_CENTER: return 17;
case SF_CHANNEL_MAP_TOP_REAR_RIGHT: return 18;
default:
throw std::runtime_error(format("Unknown channel: %d", value));
}
}
#define CHECK(expr) do { if (!(expr)) throw std::runtime_error("ERROR"); } \
while (0)
LibSndfileModule::LibSndfileModule(const std::wstring &path)
{
HMODULE hDll;
hDll = LoadLibraryW(path.c_str());
m_loaded = (hDll != NULL);
if (!m_loaded)
return;
try {
CHECK(wchar_open = ProcAddress(hDll, "sf_wchar_open"));
CHECK(open_fd = ProcAddress(hDll, "sf_open_fd"));
CHECK(close = ProcAddress(hDll, "sf_close"));
CHECK(strerror = ProcAddress(hDll, "sf_strerror"));
CHECK(command = ProcAddress(hDll, "sf_command"));
CHECK(seek = ProcAddress(hDll, "sf_seek"));
CHECK(read_short = ProcAddress(hDll, "sf_read_short"));
CHECK(read_int = ProcAddress(hDll, "sf_read_int"));
CHECK(read_float = ProcAddress(hDll, "sf_read_float"));
CHECK(read_double = ProcAddress(hDll, "sf_read_double"));
CHECK(close = ProcAddress(hDll, "sf_close"));
} catch (...) {
FreeLibrary(hDll);
m_loaded = false;
return;
}
m_module = module_t(hDll, FreeLibrary);
}
LibSndfileSource::LibSndfileSource(
const LibSndfileModule &module, const wchar_t *path)
: m_module(module)
{
SF_INFO info;
SNDFILE *fp;
if (!std::wcscmp(path, L"-"))
fp = m_module.open_fd(0, SFM_READ, &info, 0);
else {
std::wstring fullpath = get_prefixed_fullpath(path);
fp = m_module.wchar_open(fullpath.c_str(), SFM_READ, &info);
}
if (!fp)
throw std::runtime_error(m_module.strerror(0));
m_handle = handle_t(fp, m_module.close);
setRange(0, info.frames);
const char *fmtstr;
static const char *fmtmap[] = {
"", "S8LE", "S16LE", "S24LE", "S32LE", "S8LE", "F32LE", "F64LE"
};
uint32_t subformat = info.format & SF_FORMAT_SUBMASK;
if (subformat < array_size(fmtmap))
fmtstr = fmtmap[subformat];
else
throw std::runtime_error("Can't handle this kind of subformat");
SF_FORMAT_INFO finfo = { 0 };
int count;
m_module.command(fp, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof count);
for (int i = 0; i < count; ++i) {
finfo.format = i;
m_module.command(fp, SFC_GET_FORMAT_MAJOR, &finfo, sizeof finfo);
if (finfo.format == (info.format & SF_FORMAT_TYPEMASK)) {
m_format_name = finfo.extension;
break;
}
}
m_format = SampleFormat(fmtstr, info.channels, info.samplerate);
m_chanmap.resize(m_format.m_nchannels);
if (m_module.command(fp, SFC_GET_CHANNEL_MAP_INFO, &m_chanmap[0],
m_chanmap.size() * sizeof(uint32_t)) == SF_FALSE)
m_chanmap.clear();
else
std::transform(m_chanmap.begin(), m_chanmap.end(),
m_chanmap.begin(), convert_chanmap);
}
void LibSndfileSource::skipSamples(int64_t count)
{
if (m_module.seek(m_handle.get(), count, SEEK_CUR) == -1)
throw std::runtime_error("sf_seek failed");
}
#define SF_READ(type, handle, buffer, nsamples) \
m_module.read_##type(handle, reinterpret_cast<type*>(buffer), nsamples)
size_t LibSndfileSource::readSamples(void *buffer, size_t nsamples)
{
nsamples = adjustSamplesToRead(nsamples);
if (!nsamples) return 0;
nsamples *= m_format.m_nchannels;
sf_count_t rc;
if (m_format.m_bitsPerSample == 8)
rc = readSamples8(buffer, nsamples);
else if (m_format.m_bitsPerSample == 16)
rc = SF_READ(short, m_handle.get(), buffer, nsamples);
else if (m_format.m_bitsPerSample == 24)
rc = readSamples24(buffer, nsamples);
else if (m_format.m_bitsPerSample == 64)
rc = SF_READ(double, m_handle.get(), buffer, nsamples);
else if (m_format.m_type == SampleFormat::kIsSignedInteger)
rc = SF_READ(int, m_handle.get(), buffer, nsamples);
else
rc = SF_READ(float, m_handle.get(), buffer, nsamples);
nsamples = static_cast<size_t>(rc / m_format.m_nchannels);
addSamplesRead(nsamples);
return nsamples;
}
size_t LibSndfileSource::readSamples8(void *buffer, size_t nsamples)
{
std::vector<short> v(m_format.m_nchannels * nsamples);
sf_count_t rc = SF_READ(short, m_handle.get(), &v[0], nsamples);
char *bp = reinterpret_cast<char*>(buffer);
for (size_t i = 0; i < rc; ++i)
*bp++ = static_cast<char>(v[i] / 256);
return static_cast<size_t>(rc);
}
size_t LibSndfileSource::readSamples24(void *buffer, size_t nsamples)
{
std::vector<int32_t> v(m_format.m_nchannels * nsamples);
sf_count_t rc = SF_READ(int, m_handle.get(), &v[0], nsamples);
MemorySink24LE sink(buffer);
for (size_t i = 0; i < rc; ++i)
sink.put(v[i] / 256);
return static_cast<size_t>(rc);
}
Jump to Line
Something went wrong with that request. Please try again.