Skip to content

add WaveReader and WaveInfoReader#87

Merged
danpovey merged 6 commits intodanpovey:pybind11from
naxingyu:add-feat-pybind
Dec 19, 2019
Merged

add WaveReader and WaveInfoReader#87
danpovey merged 6 commits intodanpovey:pybind11from
naxingyu:add-feat-pybind

Conversation

@naxingyu
Copy link

@naxingyu naxingyu commented Dec 18, 2019

Members of wave data will be added upon future request. Currently it works like

>>> import kaldi as k
>>> import numpy as np
>>> rs = "scp:wav.scp"
>>> wave_reader = k.SequentialWaveReader(rs)
>>> wave_reader.Key()
'103-1240-0002'
>>> data = wave_reader.Value()
>>> data.Duration()
15.175000190734863
>>> wave = np.array(data.Data(), copy=False)
>>> wave = wave.reshape(data.Data().NumCols())
>>> waveform = k.FloatSubVector(wave)

@danpovey
Copy link
Owner

@cskuangfj please review

@danpovey
Copy link
Owner

sorry @csukuangfj pls review

.def("Duration", &WaveInfo::Duration)
.def("NumChannels", &WaveInfo::NumChannels)
.def("BlockAlign", &WaveInfo::BlockAlign)
.def("DataBytes", &WaveInfo::DataBytes);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure whether the binding for Read should also be included.

.def("DataBytes", &WaveInfo::DataBytes);

py::class_<WaveData>(m, "WaveData")
.def("Duration", &WaveData::Duration)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it's time-consuming to wrap every member of the class, but it's just copy and paste;
please also wrap other data members.

.def("Done", &SequentialTableReader<WaveHolder>::Done)
.def("Key", &SequentialTableReader<WaveHolder>::Key)
.def("FreeCurrent", &SequentialTableReader<WaveHolder>::FreeCurrent)
.def("Value", &SequentialTableReader<WaveHolder>::Value)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think py::return_value_policy::reference should be used for "Value",

If a function in C++ returns a pointer or a reference that does not owned by Python,
we should use py::return_value_policy::reference

@danpovey
Copy link
Owner

danpovey commented Dec 19, 2019 via email

@danpovey
Copy link
Owner

danpovey commented Dec 19, 2019 via email

@csukuangfj
Copy link

As for the documentation, a normal user who uses kaldi pybind in Python can get the help for
a specific function using help(some-function) just as normal Python code; the precondition
is that we, as the developer, have to provide the help information while binding that function.

@danpovey
Copy link
Owner

Mm. I'm still concerned that it is kind of a pain to do that (not everyone does much interactive python programming). One possibility is to have a comment block above each pybind wrapping where we write it out as if it were a native python class definition, with function signatures and documentation (but of course no implementation)? I know it would be time consuming, but it could make a big difference to how easy it is to understand the code.

@csukuangfj
Copy link

I found this
https://github.com/intel-isl/Open3D/blob/master/src/Python/open3d_pybind/docstring.h
yesterday and have not explored too far. I think it's maybe helpful.

@danpovey
Copy link
Owner

danpovey commented Dec 19, 2019 via email

@csukuangfj
Copy link

You can see the result of the generated documentation using the Open3D approach.

The C++ code written by a human:

    m_io.def("write_image",
             [](const std::string &filename, const geometry::Image &image,
                int quality) {
                 return io::WriteImage(filename, image, quality);
             },
             "Function to write Image to file", "filename"_a, "image"_a,
             "quality"_a = 90);

and the corresponding documentation generated by the machine can be found at
http://www.open3d.org/docs/release/python_api/open3d.io.write_image.html#open3d.io.write_image

I am not sure whether that is what you wanted.

@danpovey
Copy link
Owner

danpovey commented Dec 19, 2019 via email

@danpovey
Copy link
Owner

danpovey commented Dec 19, 2019 via email

@naxingyu
Copy link
Author

@csukuangfj comments resolved. I've left Read and Write methods out, since it is not necessary for feature extraction.

.def("Close", &SequentialTableReader<WaveHolder>::Close);

py::class_<RandomAccessTableReader<WaveHolder>>(m, "RandomAccessWaveReader")
.def(py::init<>())

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should the copy constructor also be wrapped?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, I see

@danpovey
Copy link
Owner

danpovey commented Dec 19, 2019 via email

@csukuangfj
Copy link

+2

@naxingyu
Copy link
Author

I added iterator and dict reader for wave in matrix_reader.py. But the module name is confusing. It's better to rename it to kaldi.reader or create seperate submodules, such as kaldi.matrix.reader and kaldi.feat.reader

@danpovey
Copy link
Owner

danpovey commented Dec 19, 2019 via email

@naxingyu
Copy link
Author

I'd like to hear @csukuangfj and @DongjiGao 's opinion since they created the basics.

@danpovey
Copy link
Owner

@DongjiGao is, like me, a relative newcomer to python binding. I think @dogancan's opinion might carry more weight if he can share it. But glad to hear from Dongji too.

@csukuangfj
Copy link

I think @dogancan, the creator of PyKaldi, is more experienced.

There are lots of useful code we can borrow from PyKaldi.

For example, for the matrix part, PyKalid uses
https://github.com/pykaldi/pykaldi/blob/master/kaldi/matrix/kaldi-matrix.clif
to wrap the methods of Matrix, and there is a separate Python file (https://github.com/pykaldi/pykaldi/blob/master/kaldi/matrix/_matrix.py)
extending the functionality of Matrix by defining a new class Matrix in Python
which inherits from the Matrix wrapped by Clif (https://github.com/pykaldi/pykaldi/blob/master/kaldi/matrix/_matrix.py#L1262)

For the I/O reader/writer part,

are great references.

@csukuangfj
Copy link

We can also follow the directory structure what PyKalid is using.

@danpovey
Copy link
Owner

danpovey commented Dec 19, 2019 via email

@csukuangfj
Copy link

Yes, PyKaldi's directory structure follows Kaldi's source code structure.
I followed PyKaldi's approach to organize the current kaldi pybind code structure.

@naxingyu
Copy link
Author

I just checked util module @dogancan shared in the group. They have all type of readers wrapped in a kaldi.util module. That seems to be a good practice. Other folders, e.g. matrix and feat only focus on the type holder.

@danpovey
Copy link
Owner

danpovey commented Dec 19, 2019 via email

@naxingyu
Copy link
Author

@danpovey how about finish this PR about wave as is and open another one to restructure the submodules?

@danpovey
Copy link
Owner

OK, will do that. Thanks for helping to push this forward!

@danpovey danpovey merged commit 8592152 into danpovey:pybind11 Dec 19, 2019
@naxingyu naxingyu deleted the add-feat-pybind branch December 19, 2019 15:29
@naxingyu naxingyu mentioned this pull request Dec 19, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants