Commit 7ba54b86 authored by André Anjos's avatar André Anjos 💬
Browse files

[multiple] Fixes compilation and testing (all good as before)

parent 5b87c15f
# import Libraries of other lib packages
import bob.io.base
# import our own Library
import bob.extension
bob.extension.load_bob_library('bob.io.audio', __file__)
from ._library import *
from . import version
from .version import module as __version__
......@@ -12,6 +8,7 @@ from .version import module as __version__
def get_config():
"""Returns a string containing the configuration information.
"""
import bob.extension
return bob.extension.get_config(__name__, version.externals)
......
......@@ -6,13 +6,16 @@
* @brief A class to help you read audio. This code is based on Sox
*/
#include "utils.h"
#include "reader.h"
#include "utils.h"
#include <stdexcept>
#include <boost/format.hpp>
#include <boost/filesystem.hpp>
#include <bob.io.base/blitz_array.h>
bob::io::audio::Reader::Reader(const char* filename) {
open(filename);
}
......@@ -43,7 +46,7 @@ void bob::io::audio::Reader::open(const char* filename) {
m_offset = m_file->tell_off; ///< start of stream
// Set typeinfo variables
m_typeinfo.dtype = bob::core::array::t_float64;
m_typeinfo.dtype = bob::io::base::array::t_float64;
m_typeinfo.nd = 2;
m_typeinfo.shape[0] = this->numberOfChannels();
m_typeinfo.shape[1] = this->numberOfSamples();
......@@ -58,9 +61,10 @@ bob::io::audio::Reader::~Reader() {
}
size_t bob::io::audio::Reader::load(blitz::Array<double,2>& data) {
bob::core::array::blitz_array tmp(data);
return load(tmp);
size_t bob::io::audio::Reader::load(blitz::Array<double,2>& data,
void (*check)(void)) {
bob::io::base::array::blitz_array tmp(data);
return load(tmp, check);
}
......@@ -71,13 +75,14 @@ void bob::io::audio::Reader::reset() {
}
size_t bob::io::audio::Reader::load(bob::io::base::array::interface& b) const {
size_t bob::io::audio::Reader::load(bob::io::base::array::interface& b,
void (*check)(void)) {
//checks if the output array shape conforms to the audio specifications,
//otherwise, throw.
if (!m_typeinfo.is_compatible(b.type())) {
boost::format s("input buffer (%s) does not conform to the audio stream size specifications (%s)");
s % b.type().str() % m_typeinfo_video.str();
s % b.type().str() % m_typeinfo.str();
throw std::runtime_error(s.str());
}
......@@ -88,11 +93,12 @@ size_t bob::io::audio::Reader::load(bob::io::base::array::interface& b) const {
shape = m_typeinfo.shape[0], m_typeinfo.shape[1];
stride = m_typeinfo.stride[0], m_typeinfo.stride[1];
blitz::Array<double,2> dst(static_cast<double*>(buffer.ptr()), shape, stride, blitz::neverDeleteData);
blitz::Array<double,2> dst(static_cast<double*>(b.ptr()), shape, stride, blitz::neverDeleteData);
auto nchan = this->numberOfChannels();
auto nsamp = this->numberOfSamples()
int nchan = this->numberOfChannels();
int nsamp = this->numberOfSamples();
for (int i=0; i<nsamp; ++i) {
if (check) check(); ///< runs user check function before we start our work
sox_read(m_file.get(), m_buffer.get(), nchan);
for (int j=0; j<nchan; ++j) {
dst(j,i) = m_buffer[j] / bob::io::audio::SOX_CONVERSION_COEF;
......
......@@ -10,10 +10,10 @@
#define BOB_IO_AUDIO_READER_H
#include <string>
#include <blitz/array.h>
#include <boost/shared_ptr.hpp>
#include <boost/shared_array.hpp>
#include <blitz/array.h>
#include <bob.io.base/array.h>
......@@ -22,7 +22,7 @@ extern "C" {
}
namespace bob { namespace io { namespace video {
namespace bob { namespace io { namespace audio {
/**
* Reader objects can read data from audio files. The current implementation
......@@ -109,14 +109,17 @@ namespace bob { namespace io { namespace video {
* Loads all of the audio stream in a blitz array organized in this way:
* (rate, samples). The 'data' parameter will be
* resized if required.
*
* The check function is used to hook a signal handler and stop
* processing if required by the user.
*/
size_t load(blitz::Array<double,2>& data) const;
size_t load(blitz::Array<double,2>& data, void (*check)(void)=0);
/**
* Loads all of the video stream in a buffer. Resizes the buffer if
* Loads all of the audio stream in a buffer. Resizes the buffer if
* the space and type are not good.
*/
size_t load(bob::io::base::array::interface& b) const;
size_t load(bob::io::base::array::interface& b, void (*check)(void)=0);
/**
* Closes the file
......@@ -145,12 +148,12 @@ namespace bob { namespace io { namespace video {
private: //our representation
std::string m_filename; ///< the name of the file we are manipulating
bob::core::array::typeinfo m_typeinfo; ///< read the audio type
bob::io::base::array::typeinfo m_typeinfo; ///< read the audio type
boost::shared_ptr<sox_format_t> m_file; ///< input file
boost::shared_array<sox_sample_t> m_buffer; ///< buffer for readout
uint64_t m_offset; ///< start of stream
};
}}
}}}
#endif /* BOB_IO_AUDIO_READER_H */
......@@ -8,7 +8,7 @@
#include "utils.h"
#include <map>
const double bob::io::audio::SOX_CONVERSION_COEF=2147483648.;
const double bob::io::audio::SOX_CONVERSION_COEF=2147483648.; /* 2^31 */
void bob::io::audio::close_sox_file(sox_format_t* f) {
sox_close(f);
......@@ -48,12 +48,12 @@ static const std::map<sox_encoding_t, std::string> ENC2STR = {
const char* bob::io::audio::encoding2string(sox_encoding_t e) {
auto it = ENC2STR.find(e);
if (e != ENC2STR.end()) return it->second;
return ENC2STR.rbegin()->second; //last entry: UNKNOWN
if (it != ENC2STR.end()) return it->second.c_str();
return ENC2STR.rbegin()->second.c_str(); //last entry: UNKNOWN
}
//requires c++11 for compiling
static const std::map<sox_encoding_t, std::string> STR2ENC = {
static const std::map<std::string, sox_encoding_t> STR2ENC = {
{"SIGN2", SOX_ENCODING_SIGN2},
{"UNSIGNED", SOX_ENCODING_UNSIGNED},
{"FLOAT", SOX_ENCODING_FLOAT},
......@@ -85,7 +85,7 @@ static const std::map<sox_encoding_t, std::string> STR2ENC = {
};
sox_encoding_t bob::io::audio::string2encoding(const char* s) {
auto it = STR2ENC.find(e);
if (e != STR2ENC.end()) return it->second;
auto it = STR2ENC.find(s);
if (it != STR2ENC.end()) return it->second;
return STR2ENC.rbegin()->second; //last entry: UNKNOWN
}
......@@ -17,7 +17,7 @@ extern "C" {
namespace bob { namespace io { namespace audio {
const double SOX_CONVERSION_COEF;
extern const double SOX_CONVERSION_COEF;
void close_sox_file(sox_format_t* f);
......
......@@ -107,7 +107,7 @@ bob::io::audio::Writer::Writer(const char* filename, double rate,
m_file = boost::shared_ptr<sox_format_t>(f, std::ptr_fun(bob::io::audio::close_sox_file));
m_typeinfo.dtype = bob::core::array::t_float64;
m_typeinfo.dtype = bob::io::base::array::t_float64;
m_typeinfo.nd = 2;
m_typeinfo.shape[0] = 0;
m_typeinfo.shape[1] = 0;
......@@ -134,7 +134,7 @@ void bob::io::audio::Writer::append(const blitz::Array<double,1>& data) {
}
//checks data specifications
if (m_typeinfo.shape[0] != data.extent(0)) {
if (m_typeinfo.shape[0] != (size_t)data.extent(0)) {
boost::format m("input sample size for file `%s' should be (%d,)");
m % m_filename % m_typeinfo.shape[0];
throw std::runtime_error(m.str());
......@@ -145,7 +145,7 @@ void bob::io::audio::Writer::append(const blitz::Array<double,1>& data) {
sox_write(m_file.get(), m_buffer.get(), m_typeinfo.shape[0]);
// updates internal counters
m_signal_cache.length += m_file->signal.channels;
m_file->signal.length += m_file->signal.channels;
m_typeinfo.shape[1] += 1;
m_typeinfo.update_strides();
}
......@@ -166,7 +166,7 @@ void bob::io::audio::Writer::append(const blitz::Array<double,2>& data) {
}
//checks data specifications
if (m_typeinfo.shape[0] != data.extent(0)) {
if (m_typeinfo.shape[0] != (size_t)data.extent(0)) {
boost::format m("input sample size for file `%s' should have %d rows");
m % m_filename % m_typeinfo.shape[0];
throw std::runtime_error(m.str());
......@@ -179,7 +179,7 @@ void bob::io::audio::Writer::append(const blitz::Array<double,2>& data) {
}
// updates internal counters
m_signal_cache.length += data.extent(1) * m_file->signal.channels;
m_file->signal.length += data.extent(1) * m_file->signal.channels;
m_typeinfo.shape[1] += data.extent(1);
m_typeinfo.update_strides();
}
......
......@@ -9,6 +9,7 @@
#ifndef BOB_IO_AUDIO_WRITER_H
#define BOB_IO_AUDIO_WRITER_H
#include <map>
#include <string>
#include <blitz/array.h>
......@@ -22,10 +23,10 @@ extern "C" {
}
namespace bob { namespace io { namespace video {
namespace bob { namespace io { namespace audio {
/* Until we can get a better handle (requires C++-11 initializers) */
const std::map<std::string, std::string> SUPPORTED_FORMATS;
extern const std::map<std::string, std::string> SUPPORTED_FORMATS;
/**
* Use objects of this class to create and write audio files.
......@@ -45,7 +46,8 @@ namespace bob { namespace io { namespace video {
* @param bits_per_sample What-it-says...
*/
Writer(const char* filename, double rate=8000,
sox_encoding_t encoding=UNSIGNED, size_t bits_per_sample=16);
sox_encoding_t encoding=SOX_ENCODING_UNKNOWN,
size_t bits_per_sample=16);
/**
* Destructor virtualization
......@@ -113,7 +115,7 @@ namespace bob { namespace io { namespace video {
/**
* Returns the typing information for the audio file
*/
inline const bob::core::array::typeinfo& type() const
inline const bob::io::base::array::typeinfo& type() const
{ return m_typeinfo; }
/**
......
......@@ -29,20 +29,19 @@ class AudioFile: public bob::io::base::File {
m_newfile(true) {
if (mode == 'r') {
m_reader = boost::make_shared<bob::io::audio::Reader>(m_filename);
m_reader = boost::make_shared<bob::io::audio::Reader>(m_filename.c_str());
m_newfile = false;
}
else if (mode == 'a' && boost::filesystem::exists(path)) {
// to be able to append must load all data and save in audio::Writer
m_reader = boost::make_shared<bob::io::audio::Reader>(m_filename);
m_reader = boost::make_shared<bob::io::audio::Reader>(m_filename.c_str());
bob::io::base::array::blitz_array data(m_reader->type());
m_reader->load(data);
auto rate = m_reader->rate();
auto encoding = m_reader->encoding();
auto bps = m_reader->bitsPerSample();
m_reader.reset(); ///< cleanup before truncating the file
m_writer = boost::make_shared<bob::io::audio::Writer>(m_filename,
rate, encoding, bps);
m_writer = boost::make_shared<bob::io::audio::Writer>(m_filename.c_str(), rate, encoding, bps);
m_writer->append(data); ///< we are now ready to append
m_newfile = false;
}
......@@ -100,7 +99,7 @@ class AudioFile: public bob::io::base::File {
throw std::runtime_error("input buffer for audio input must have either 1 (channel values for 1 sample) or 2 dimensions (channels, samples)");
if(m_newfile) {
m_writer = boost::make_shared<bob::io::audio::Writer>(m_filename);
m_writer = boost::make_shared<bob::io::audio::Writer>(m_filename.c_str());
}
if(!m_writer)
......
......@@ -86,7 +86,7 @@ static int PyBobIoAudioReader_Init(PyBobIoAudioReaderObject* self,
#endif
try {
self->v.reset(new bob::io::audio::Reader(c_filename, check));
self->v.reset(new bob::io::audio::Reader(c_filename));
}
catch (std::exception& e) {
PyErr_SetString(PyExc_RuntimeError, e.what());
......@@ -156,15 +156,15 @@ PyDoc_STRVAR(s_compression_factor_str, "compressionfactor");
PyDoc_STRVAR(s_compression_factor_doc,
"[float] Compression factor on the audio stream");
PyObject* PyBobIoAudioReader_Encoding(PyBobIoAudioReaderObject* self) {
return Py_BuildValue("s", bob::io::audio::encoding2string(self->v->encoding()).c_str());
PyObject* PyBobIoAudioReader_EncodingName(PyBobIoAudioReaderObject* self) {
return Py_BuildValue("s", bob::io::audio::encoding2string(self->v->encoding()));
}
PyDoc_STRVAR(s_encoding_name_str, "encoding");
PyDoc_STRVAR(s_encoding_name_doc,
"[str] Name of the encoding in which this audio file was recorded in");
PyObject* PyBobIoAudioReader_Type(PyBobIoAudioReaderObject* self) {
PyObject* PyBobIoAudioReader_TypeInfo(PyBobIoAudioReaderObject* self) {
return PyBobIo_TypeInfoAsTuple(self->v->type());
}
......@@ -216,10 +216,10 @@ static PyGetSetDef PyBobIoAudioReader_getseters[] = {
0,
},
{
s_encoding_str,
(getter)PyBobIoAudioReader_Encoding,
s_encoding_name_str,
(getter)PyBobIoAudioReader_EncodingName,
0,
s_encoding_doc,
s_encoding_name_doc,
0,
},
{
......@@ -231,7 +231,7 @@ static PyGetSetDef PyBobIoAudioReader_getseters[] = {
},
{
s_type_str,
(getter)PyBobIoAudioReader_Type,
(getter)PyBobIoAudioReader_TypeInfo,
0,
s_type_doc,
0,
......@@ -246,7 +246,7 @@ static PyObject* PyBobIoAudioReader_Repr(PyBobIoAudioReaderObject* self) {
# else
PyString_FromFormat
# endif
("%s(filename='%s')", Py_TYPE(self)->tp_name, self->v->filename().c_str());
("%s(filename='%s')", Py_TYPE(self)->tp_name, self->v->filename());
}
/**
......@@ -281,24 +281,24 @@ static PyObject* PyBobIoAudioReader_Load(PyBobIoAudioReaderObject* self, PyObjec
if (!retval) return 0;
auto retval_ = make_safe(retval);
Py_ssize_t frames_read = 0;
Py_ssize_t samples_read = 0;
try {
bobskin skin((PyArrayObject*)retval, info.dtype);
frames_read = self->v->load(skin, raise_on_error, &Check_Interrupt);
samples_read = self->v->load(skin, &Check_Interrupt);
}
catch (std::exception& e) {
if (!PyErr_Occurred()) PyErr_SetString(PyExc_RuntimeError, e.what());
return 0;
}
catch (...) {
if (!PyErr_Occurred()) PyErr_Format(PyExc_RuntimeError, "caught unknown exception while reading audio from file `%s'", self->v->filename().c_str());
if (!PyErr_Occurred()) PyErr_Format(PyExc_RuntimeError, "caught unknown exception while reading audio from file `%s'", self->v->filename());
return 0;
}
if (frames_read != shape[0]) {
if (samples_read != shape[1]) {
//resize
shape[0] = frames_read;
shape[1] = samples_read;
PyArray_Dims newshape;
newshape.ptr = shape;
newshape.len = info.nd;
......
......@@ -10,82 +10,76 @@
"""Tests audio reader and writer based on sox for bob and python
"""
import os, sys
import unittest
import os
import nose.tools
import pkg_resources
import scipy.io.wavfile
import numpy
import pkg_resources
import .
from ._ext import reader
def F(name, f):
"""Returns the test file on the "data" subdirectory"""
return pkg_resources.resource_filename(name, os.path.join('data', f))
import bob.io.base
import bob.io.matlab
from . import reader, writer
class SoxTest(unittest.TestCase):
"""Performs various tests on audio reading and writing using sox for bob and python"""
def F(f):
"""Returns the test file on the "data" subdirectory"""
return pkg_resources.resource_filename(__name__, os.path.join('data', f))
def run_for(self, sample, extension):
# audio file name
infile = F(__name__, '%s%s' % (sample, extension))
def run_for(fname):
# reading the file using xbob.sox
sox_audio = reader(infile)
(sox_rate, sox_data) = sox_audio.load()
# audio file name
infile = F(fname)
# reading the file using scipy.io.wavfile
(scipy_rate, scipy_data)=scipy.io.wavfile.read(infile)
# reading the file using our SoX bindings
f = reader(infile)
data = f.load()
# verify if the rates are the same
self.assertTrue(numpy.equal(int(sox_rate), scipy_rate))
# reading the file using scipy.io.wavfile
(scipy_rate, scipy_data) = scipy.io.wavfile.read(infile)
# If one channel
if sox_data.shape[0] == 1:
# verify if the data are the same (x 2^15)
sox_data_ = sox_data[0] * pow(2,15)
sox_data_.astype(int)
self.assertTrue(numpy.array_equal(sox_data_, scipy_data))
# verify if the rates are the same
nose.tools.eq_(int(f.rate), scipy_rate)
#If more than one channel
elif sox_data.shape[0] > 1:
# verify if the nchannels are the same
self.assertTrue(numpy.equal(sox_data.shape[0], scipy_data.shape[1]))
# If one channel
if data.shape[0] == 1:
# verify if the data are the same (x 2^15)
assert numpy.array_equal((data[0]*pow(2,15)).astype(int), scipy_data)
# verify if the data are the same (x 2^15)
for i in range(0, sox_data.shape[0]):
sox_data_ = sox_data[i] * pow(2,15)
sox_data_.astype(int)
scipy_data_ = scipy_data[:,i]
self.assertTrue(numpy.array_equal(sox_data_, scipy_data_))
# If more than one channel
elif data.shape[0] > 1:
# verify if the nchannels are the same
nose.tools.eq_(data.shape[0], scipy_data.shape[1])
# verify if the data are the same (x 2^15)
for i in range(data.shape[0]):
assert numpy.array_equal((data[i]*pow(2,15)).astype(int), scipy_data[:,i])
# compare mono: ours vs scipy.io.wavfile
def test01_read_mono_wav(self):
self.run_for('sample1', '.wav')
def test_read_mono_wav():
run_for('sample1.wav')
# compare stereo: ours vs scipy.io.wavfile
def test02_read_stereo_wav(self):
self.run_for('sample4', '.wav')
def test_read_stereo_wav():
run_for('sample4.wav')
# compare mono: ours vs matlab
def test03_read_mono_wav(self):
def test_read_mono_wav_matlab():
# audio file name
infile = F(__name__, 'sample3.wav')
# audio file name
infile = F('sample3.wav')
# reading the file using xbob.sox
sox_audio = reader(infile)
(sox_rate, sox_data) = sox_audio.load()
# reading the file using xbob.sox
f = reader(infile)
data = f.load()
# reading the .mat file that contains the data generated by the Matlab wavread function
mat_data = bob.io.load(F(__name__, 'sample3.mat'))
self.assertTrue(numpy.array_equal(sox_data, mat_data))
# reading the .mat file that contains the data generated by the Matlab
# wavread function
mat_data = bob.io.base.load(F('sample3.mat'))
assert numpy.array_equal(data, mat_data)
# TODO: could add test for writing
# TODO: could add test for writing
......@@ -6,6 +6,7 @@
*/
#define BOB_IMPORT_VERSION
#include <cstring>
#include <bob.blitz/config.h>
#include <bob.blitz/cleanup.h>
#include <bob.core/config.h>
......@@ -23,7 +24,7 @@ static int dict_set(PyObject* d, const char* key, const char* value) {
/**
* SoX version
*/
static PyObject* sox_version() {
static PyObject* py_sox_version() {
PyObject* retval = PyDict_New();
if (!retval) return 0;
auto retval_ = make_safe(retval);
......@@ -41,7 +42,7 @@ static PyObject* build_version_dictionary() {
if (!retval) return 0;
auto retval_ = make_safe(retval);
if (!dict_steal(retval, "SoX", sox_version())) return 0;
if (!dict_steal(retval, "SoX", py_sox_version())) return 0;
if (!dict_steal(retval, "Boost", boost_version())) return 0;
if (!dict_steal(retval, "Compiler", compiler_version())) return 0;
if (!dict_steal(retval, "Python", python_version())) return 0;
......
......@@ -94,7 +94,7 @@ static int PyBobIoAudioWriter_Init(PyBobIoAudioWriterObject* self,
auto filename_ = make_safe(filename);
std::string encoding_str = encoding?encoding:"UNSIGNED";
sox_encoding_t sox_encoding = bob::io::audio::string2encoding(encoding_str);
sox_encoding_t sox_encoding = bob::io::audio::string2encoding(encoding_str.c_str());
#if PY_VERSION_HEX >= 0x03000000
const char* c_filename = PyBytes_AS_STRING(filename);
......@@ -174,15 +174,15 @@ PyDoc_STRVAR(s_compression_factor_str, "compressionfactor");
PyDoc_STRVAR(s_compression_factor_doc,
"[float] Compression factor on the audio stream");
PyObject* PyBobIoAudioWriter_Encoding(PyBobIoAudioWriterObject* self) {
return Py_BuildValue("s", bob::io::audio::encoding2string(self->v->encoding()).c_str());
PyObject* PyBobIoAudioWriter_EncodingName(PyBobIoAudioWriterObject* self) {
return Py_BuildValue("s", bob::io::audio::encoding2string(self->v->encoding()));
}
PyDoc_STRVAR(s_encoding_name_str, "encoding");
PyDoc_STRVAR(s_encoding_name_doc,
"[str] Name of the encoding in which this audio file was recorded in");
PyObject* PyBobIoAudioWriter_Type(PyBobIoAudioWriterObject* self) {
PyObject* PyBobIoAudioWriter_TypeInfo(PyBobIoAudioWriterObject* self) {
return PyBobIo_TypeInfoAsTuple(self->v->type());
}
......@@ -244,10 +244,10 @@ static PyGetSetDef PyBobIoAudioWriter_getseters[] = {
0,
},
{
s_encoding_str,
(getter)PyBobIoAudioWriter_Encoding,
s_encoding_name_str,
(getter)PyBobIoAudioWriter_EncodingName,
0,
s_encoding_doc,
s_encoding_name_doc,
0,
},
{
......@@ -259,7 +259,7 @@ static PyGetSetDef PyBobIoAudioWriter_getseters[] = {
},
{
s_type_str,
(getter)PyBobIoAudioWriter_Type,
(getter)PyBobIoAudioWriter_TypeInfo,
0,
s_type_doc,
0,
......@@ -277,7 +277,7 @@ static PyGetSetDef PyBobIoAudioWriter_getseters[] = {
static PyObject* PyBobIoAudioWriter_Repr(PyBobIoAudioWriterObject* self) {
if (!self->v->is_opened()) {
PyErr_Format(PyExc_RuntimeError, "`%s' for `%s' is closed",
Py_TYPE(self)->tp_name, self->v->filename().c_str());
Py_TYPE(self)->tp_name, self->v->filename());
return 0;
}