inline void init_resampled_readable_audio_file()

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``.");
}