in pedalboard/io/ResampledReadableAudioFile.h [487:666]
inline void init_resampled_readable_audio_file(
py::module &m, py::class_<ResampledReadableAudioFile, AudioFile,
std::shared_ptr<ResampledReadableAudioFile>>
&pyResampledReadableAudioFile) {
pyResampledReadableAudioFile
.def(py::init(
[](std::shared_ptr<ReadableAudioFile> audioFile,
float targetSampleRate,
ResamplingQuality quality) -> ResampledReadableAudioFile * {
// This definition is only here to provide nice docstrings.
throw std::runtime_error(
"Internal error: __init__ should never be called, as this "
"class implements __new__.");
}),
py::arg("audio_file"), py::arg("target_sample_rate"),
py::arg("resampling_quality") = ResamplingQuality::WindowedSinc32)
.def_static(
"__new__",
[](const py::object *, std::shared_ptr<ReadableAudioFile> audioFile,
float targetSampleRate, ResamplingQuality quality) {
return std::make_shared<ResampledReadableAudioFile>(
audioFile, targetSampleRate, quality);
},
py::arg("cls"), py::arg("audio_file"), py::arg("target_sample_rate"),
py::arg("resampling_quality") = ResamplingQuality::WindowedSinc32)
.def("read", &ResampledReadableAudioFile::read, py::arg("num_frames") = 0,
R"(
Read the given number of frames (samples in each channel, at the target sample rate)
from this audio file at its current position, automatically resampling on-the-fly to
``target_sample_rate``.
``num_frames`` is a required argument, as audio files can be deceptively large. (Consider that
an hour-long ``.ogg`` file may be only a handful of megabytes on disk, but may decompress to
nearly a gigabyte in memory.) Audio files should be read in chunks, rather than all at once, to avoid
hard-to-debug memory problems and out-of-memory crashes.
Audio samples are returned as a multi-dimensional :class:`numpy.array` with the shape
``(channels, samples)``; i.e.: a stereo audio file will have shape ``(2, <length>)``.
Returned data is always in the ``float32`` datatype.
If the file does not contain enough audio data to fill ``num_frames``, the returned
:class:`numpy.array` will contain as many frames as could be read from the file. (In some cases,
passing :py:attr:`frames` as ``num_frames`` may still return less data than expected. See documentation
for :py:attr:`frames` and :py:attr:`exact_duration_known` for more information about situations
in which this may occur.)
For most (but not all) audio files, the minimum possible sample value will be ``-1.0f`` and the
maximum sample value will be ``+1.0f``.
.. note::
For convenience, the ``num_frames`` argument may be a floating-point number. However, if the
provided number of frames contains a fractional part (i.e.: ``1.01`` instead of ``1.00``) then
an exception will be thrown, as a fractional number of samples cannot be returned.
)")
.def("seekable", &ResampledReadableAudioFile::isSeekable,
"Returns True if this file is currently open and calls to seek() "
"will work.")
.def("seek", &ResampledReadableAudioFile::seek, py::arg("position"),
"Seek this file to the provided location in frames at the target "
"sample rate. Future reads will start from this position.\n\n.. "
"note::\n Prior to version 0.7.3, this method operated in linear "
"time with respect to the seek position (i.e.: the file was seeked "
"to its beginning and pushed through the resampler) to ensure that "
"the resampled audio output was sample-accurate. This was optimized "
"in version 0.7.3 to operate in effectively constant time while "
"retaining sample-accuracy.")
.def("tell", &ResampledReadableAudioFile::tell,
"Return the current position of the read pointer in this audio "
"file, in frames at the target sample rate. This value will "
"increase as :meth:`read` is "
"called, and may decrease if :meth:`seek` is called.")
.def("close", &ResampledReadableAudioFile::close,
"Close this file, rendering this object unusable. Note that the "
":class:`ReadableAudioFile` instance that is wrapped by this object "
"will not be closed, and will remain usable.")
.def("__enter__", &ResampledReadableAudioFile::enter,
"Use this :class:`ResampledReadableAudioFile` as a context manager, "
"automatically closing the file and releasing resources when the "
"context manager exits.")
.def("__exit__", &ResampledReadableAudioFile::exit,
"Stop using this :class:`ResampledReadableAudioFile` as a context "
"manager, close the file, release its resources.")
.def("__repr__",
[](const ResampledReadableAudioFile &file) {
std::ostringstream ss;
ss << "<pedalboard.io.ResampledReadableAudioFile";
if (file.getFilename() && !file.getFilename()->empty()) {
ss << " filename=\"" << *file.getFilename() << "\"";
} else if (PythonInputStream *stream =
file.getPythonInputStream()) {
ss << " file_like=" << stream->getRepresentation();
}
if (file.isClosed()) {
ss << " closed";
} else {
ss << " samplerate=" << file.getSampleRateAsDouble();
ss << " num_channels=" << file.getNumChannels();
ss << " frames=" << file.getLengthInSamples();
ss << " file_dtype=" << file.getFileDatatype();
}
ss << " at " << &file;
ss << ">";
return ss.str();
})
.def_property_readonly(
"name", &ResampledReadableAudioFile::getFilename,
"The name of this file.\n\nIf the "
":class:`ReadableAudioFile` wrapped by this "
":class:`ResampledReadableAudioFile` was "
"opened from a file-like object, this will be ``None``.")
.def_property_readonly(
"closed", &ResampledReadableAudioFile::isClosed,
"True iff either this file or its wrapped :class:`ReadableAudioFile` "
"instance are closed (and no longer usable), False otherwise.")
.def_property_readonly(
"samplerate", &ResampledReadableAudioFile::getSampleRate,
"The sample rate of this file in samples (per channel) per second "
"(Hz). This will be equal to the ``target_sample_rate`` parameter "
"passed when this object was created. Sample rates are represented "
"as floating-point numbers by default, but this property will be an "
"integer if the file's target sample rate has no fractional part.")
.def_property_readonly("num_channels",
&ResampledReadableAudioFile::getNumChannels,
"The number of channels in this file.")
.def_property_readonly("exact_duration_known",
&ResampledReadableAudioFile::exactDurationKnown,
R"(
Returns :py:const:`True` if this file's :py:attr:`frames` and
:py:attr:`duration` attributes are exact values, or :py:const:`False` if the
:py:attr:`frames` and :py:attr:`duration` attributes are estimates based
on the file's size and bitrate.
:py:attr:`exact_duration_known` will change from :py:const:`False` to
:py:const:`True` as the file is read to completion. Once :py:const:`True`,
this value will not change back to :py:const:`False` for the same
:py:class:`AudioFile` object (even after calls to :meth:`seek`).
.. note::
:py:attr:`exact_duration_known` will only ever be :py:const:`False`
when reading certain MP3 files. For files in other formats than MP3,
:py:attr:`exact_duration_known` will always be equal to :py:const:`True`.
*Introduced in v0.7.2.*
)")
.def_property_readonly(
"frames", &ResampledReadableAudioFile::getLengthInSamples,
"The total number of frames (samples per "
"channel) in this file, at the target sample rate.\n\nFor example, "
"if this file contains 10 seconds of stereo audio at sample "
"rate of 44,100 Hz, and ``target_sample_rate`` is 22,050 Hz, "
"``frames`` will return ``22,050``.\n\nNote that different "
"``resampling_quality`` values used for resampling may cause "
"``frames`` to differ by ± 1 from its expected value.\n\n.. "
"warning::\n When reading certain MP3 files, the "
":py:attr:`frames` and :py:attr:`duration` properties may "
"initially be estimates and **may change as the file is read**. "
"See the documentation for :py:attr:`.ReadableAudioFile.frames` "
"for more details.")
.def_property_readonly(
"duration", &ResampledReadableAudioFile::getDuration,
"The duration of this file in seconds (``frames`` "
"divided by ``samplerate``).\n\n.. "
"warning::\n When reading certain MP3 files, the "
":py:attr:`frames` and :py:attr:`duration` properties may "
"initially be estimates and **may change as the file is read**. "
"See the documentation for :py:attr:`.ReadableAudioFile.frames` "
"for more details.")
.def_property_readonly(
"file_dtype", &ResampledReadableAudioFile::getFileDatatype,
"The data type (``\"int16\"``, ``\"float32\"``, etc) stored "
"natively by this file.\n\nNote that :meth:`read` will always "
"return a ``float32`` array, regardless of the value of this "
"property.")
.def_property_readonly(
"resampling_quality", &ResampledReadableAudioFile::getQuality,
"The resampling algorithm used to resample from the original file's "
"sample rate to the ``target_sample_rate``.");
}