Showing the changes to python (1 of 1 file). Show all
Unified · Split
| @@ -16,68 +16,316 @@ typedef struct · 15 unmodified lines | |||
| 16 | } Py_source; | 16 | } Py_source; |
| 17 | 17 | ||
| 18 | static char Py_source_doc[] = "" | 18 | static char Py_source_doc[] = "" |
| 19 | " __new__(path, samplerate = 0, hop_size = 512, channels = 1)\n" | 19 | "source(path, samplerate=0, hop_size=512, channels=0)\n" |
| 20 | "\n" | 20 | "\n" |
| 21 | " Create a new source, opening the given path for reading.\n" | 21 | "Create a new source, opening the given pathname for reading.\n" |
| 22 | "\n" | 22 | "\n" |
| 23 | " Examples\n" | 23 | "`source` open the file specified in `path` and creates a callable\n" |
| 24 | " --------\n" | 24 | "returning `hop_size` new audio samples at each invocation.\n" |
| 25 | "\n" | 25 | "\n" |
| 26 | " Create a new source, using the original samplerate, with hop_size = 512:\n" | 26 | "If `samplerate=0` (default), the original sampling rate of `path`\n" |
| 27 | "will be used. Otherwise, the output audio samples will be\n" | ||
| 28 | "resampled at the desired sampling-rate.\n" | ||
| 27 | "\n" | 29 | "\n" |
| 28 | " >>> source('/tmp/t.wav')\n" | 30 | "If `channels=0` (default), the original number of channels\n" |
| 31 | "in `path` will be used. Otherwise, the output audio samples\n" | ||
| 32 | "will be down-mixed or up-mixed to the desired number of\n" | ||
| 33 | "channels.\n" | ||
| 29 | "\n" | 34 | "\n" |
| 30 | " Create a new source, resampling the original to 8000Hz:\n" | 35 | "If `path` is a URL, a remote connection will be attempted to\n" |
| 36 | "open the resource and stream data from it.\n" | ||
| 31 | "\n" | 37 | "\n" |
| 32 | " >>> source('/tmp/t.wav', samplerate = 8000)\n" | 38 | "The parameter `hop_size` determines how many samples should be\n" |
| 39 | "read at each consecutive calls.\n" | ||
| 33 | "\n" | 40 | "\n" |
| 34 | " Create a new source, resampling it at 32000Hz, hop_size = 32:\n" | 41 | "Parameters\n" |
| 42 | "----------\n" | ||
| 43 | "path : str\n" | ||
| 44 | " pathname (or URL) of the file to be opened for reading\n" | ||
| 45 | "samplerate : int, optional\n" | ||
| 46 | " sampling rate of the file\n" | ||
| 47 | "hop_size : int, optional\n" | ||
| 48 | " number of samples to be read per iteration\n" | ||
| 49 | "channels : int, optional\n" | ||
| 50 | " number of channels of the file\n" | ||
| 35 | "\n" | 51 | "\n" |
| 36 | " >>> source('/tmp/t.wav', samplerate = 32000, hop_size = 32)\n" | 52 | "Examples\n" |
| 53 | "--------\n" | ||
| 54 | "By default, when only `path` is given, the file will be opened\n" | ||
| 55 | "with its original sampling rate and channel:\n" | ||
| 37 | "\n" | 56 | "\n" |
| 38 | " Create a new source, using its original samplerate:\n" | 57 | ">>> src = aubio.source('stereo.wav')\n" |
| 58 | ">>> src.uri, src.samplerate, src.channels, src.duration\n" | ||
| 59 | "('stereo.wav', 48000, 2, 86833)\n" | ||
| 39 | "\n" | 60 | "\n" |
| 40 | " >>> source('/tmp/t.wav', samplerate = 0)\n" | 61 | "A typical loop to read all samples from a local file could\n" |
| 62 | "look like this:\n" | ||
| 41 | "\n" | 63 | "\n" |
| 42 | " __call__()\n" | 64 | ">>> src = aubio.source('stereo.wav')\n" |
| 43 | " vec, read = x() <==> vec, read = x.do()\n" | 65 | ">>> total_read = 0\n" |
| 66 | ">>> while True:\n" | ||
| 67 | "... samples, read = src()\n" | ||
| 68 | "... # do something with samples\n" | ||
| 69 | "... total_read += read\n" | ||
| 70 | "... if read < src.hop_size:\n" | ||
| 71 | "... break\n" | ||
| 72 | "...\n" | ||
| 44 | "\n" | 73 | "\n" |
| 45 | " Read vector from source.\n" | 74 | "In a more Pythonic way, it can also look like this:\n" |
| 46 | "\n" | 75 | "\n" |
| 47 | " See also\n" | 76 | ">>> total_read = 0\n" |
| 48 | " --------\n" | 77 | ">>> with aubio.source('stereo.wav') as src:\n" |
| 49 | " aubio.source.do\n" | 78 | "... for frames in src:\n" |
| 50 | "\n"; | 79 | "... total_read += samples.shape[-1]\n" |
| 80 | "...\n" | ||
| 81 | "\n" | ||
| 82 | ".. rubric:: Basic interface\n" | ||
| 83 | "\n" | ||
| 84 | "`source` is a **callable**; its :meth:`__call__` method\n" | ||
| 85 | "returns a tuple containing:\n" | ||
| 86 | "\n" | ||
| 87 | "- a vector of shape `(hop_size,)`, filled with the `read` next\n" | ||
| 88 | " samples available, zero-padded if `read < hop_size`\n" | ||
| 89 | "- `read`, an integer indicating the number of samples read\n" | ||
| 90 | "\n" | ||
| 91 | "To read the first `hop_size` samples from the source, simply call\n" | ||
| 92 | "the instance itself, with no argument:\n" | ||
| 93 | "\n" | ||
| 94 | ">>> src = aubio.source('song.ogg')\n" | ||
| 95 | ">>> samples, read = src()\n" | ||
| 96 | ">>> samples.shape, read, src.hop_size\n" | ||
| 97 | "((512,), 512, 512)\n" | ||
| 98 | "\n" | ||
| 99 | "The first call returned the slice of samples `[0 : hop_size]`.\n" | ||
| 100 | "The next call will return samples `[hop_size: 2*hop_size]`.\n" | ||
| 101 | "\n" | ||
| 102 | "After several invocations of :meth:`__call__`, when reaching the end\n" | ||
| 103 | "of the opened stream, `read` might become less than `hop_size`:\n" | ||
| 104 | "\n" | ||
| 105 | ">>> samples, read = src()\n" | ||
| 106 | ">>> samples.shape, read\n" | ||
| 107 | "((512,), 354)\n" | ||
| 108 | "\n" | ||
| 109 | "The end of the vector `samples` is filled with zeros.\n" | ||
| 110 | "\n" | ||
| 111 | "After the end of the stream, `read` will be `0` since no more\n" | ||
| 112 | "samples are available:\n" | ||
| 113 | "\n" | ||
| 114 | ">>> samples, read = src()\n" | ||
| 115 | ">>> samples.shape, read\n" | ||
| 116 | "((512,), 0)\n" | ||
| 117 | "\n" | ||
| 118 | "**Note**: when the source has more than one channels, they\n" | ||
| 119 | "are be down-mixed to mono when invoking :meth:`__call__`.\n" | ||
| 120 | "To read from each individual channel, see :meth:`__next__`.\n" | ||
| 121 | "\n" | ||
| 122 | ".. rubric:: ``for`` statements\n" | ||
| 123 | "\n" | ||
| 124 | "The `source` objects are **iterables**. This allows using them\n" | ||
| 125 | "directly in a ``for`` loop, which calls :meth:`__next__` until\n" | ||
| 126 | "the end of the stream is reached:\n" | ||
| 127 | "\n" | ||
| 128 | ">>> src = aubio.source('stereo.wav')\n" | ||
| 129 | ">>> for frames in src:\n" | ||
| 130 | ">>> print (frames.shape)\n" | ||
| 131 | "...\n" | ||
| 132 | "(2, 512)\n" | ||
| 133 | "(2, 512)\n" | ||
| 134 | "(2, 230)\n" | ||
| 135 | "\n" | ||
| 136 | "**Note**: When `next(self)` is called on a source with multiple\n" | ||
| 137 | "channels, an array of shape `(channels, read)` is returned,\n" | ||
| 138 | "unlike with :meth:`__call__` which always returns the down-mixed\n" | ||
| 139 | "channels.\n" | ||
| 140 | "\n" | ||
| 141 | "If the file is opened with a single channel, `next(self)` returns\n" | ||
| 142 | "an array of shape `(read,)`:\n" | ||
| 143 | "\n" | ||
| 144 | ">>> src = aubio.source('stereo.wav', channels=1)\n" | ||
| 145 | ">>> next(src).shape\n" | ||
| 146 | "(512,)\n" | ||
| 147 | "\n" | ||
| 148 | ".. rubric:: ``with`` statements\n" | ||
| 149 | "\n" | ||
| 150 | "The `source` objects are **context managers**, which allows using\n" | ||
| 151 | "them in ``with`` statements:\n" | ||
| 152 | "\n" | ||
| 153 | ">>> with aubio.source('audiotrack.wav') as source:\n" | ||
| 154 | "... n_frames=0\n" | ||
| 155 | "... for samples in source:\n" | ||
| 156 | "... n_frames += len(samples)\n" | ||
| 157 | "... print('read', n_frames, 'samples in', samples.shape[0], 'channels',\n" | ||
| 158 | "... 'from file \"\%s\"' \% source.uri)\n" | ||
| 159 | "...\n" | ||
| 160 | "read 239334 samples in 2 channels from file \"audiotrack.wav\"\n" | ||
| 161 | "\n" | ||
| 162 | "The file will be closed before exiting the statement.\n" | ||
| 163 | "\n" | ||
| 164 | "See also the methods implementing the context manager,\n" | ||
| 165 | ":meth:`__enter__` and :meth:`__exit__`.\n" | ||
| 166 | "\n" | ||
| 167 | ".. rubric:: Seeking and closing\n" | ||
| 168 | "\n" | ||
| 169 | "At any time, :meth:`seek` can be used to move to any position in\n" | ||
| 170 | "the file. For instance, to rewind to the start of the stream:\n" | ||
| 171 | "\n" | ||
| 172 | ">>> src.seek(0)\n" | ||
| 173 | "\n" | ||
| 174 | "The opened file will be automatically closed when the object falls\n" | ||
| 175 | "out of scope and is scheduled for garbage collection.\n" | ||
| 176 | "\n" | ||
| 177 | "In some cases, it is useful to manually :meth:`close` a given source,\n" | ||
| 178 | "for instance to limit the number of simultaneously opened files:\n" | ||
| 179 | "\n" | ||
| 180 | ">>> src.close()\n" | ||
| 181 | "\n" | ||
| 182 | ".. rubric:: Input formats\n" | ||
| 183 | "\n" | ||
| 184 | "Depending on how aubio was compiled, :class:`source` may or may not\n" | ||
| 185 | "open certain **files format**. Below are some examples that assume\n" | ||
| 186 | "support for compressed files and remote urls was compiled in:\n" | ||
| 187 | "\n" | ||
| 188 | "- open a local file using its original sampling rate and channels,\n" | ||
| 189 | " and with the default hop size:\n" | ||
| 190 | "\n" | ||
| 191 | ">>> s = aubio.source('sample.wav')\n" | ||
| 192 | ">>> s.uri, s.samplerate, s.channels, s.hop_size\n" | ||
| 193 | "('sample.wav', 44100, 2, 512)\n" | ||
| 194 | "\n" | ||
| 195 | "- open a local compressed audio file, resampling to 32000Hz if needed:\n" | ||
| 196 | "\n" | ||
| 197 | ">>> s = aubio.source('song.mp3', samplerate=32000)\n" | ||
| 198 | ">>> s.uri, s.samplerate, s.channels, s.hop_size\n" | ||
| 199 | "('song.mp3', 32000, 2, 512)\n" | ||
| 200 | "\n" | ||
| 201 | "- open a local video file, down-mixing and resampling it to 16kHz:\n" | ||
| 202 | "\n" | ||
| 203 | ">>> s = aubio.source('movie.mp4', samplerate=16000, channels=1)\n" | ||
| 204 | ">>> s.uri, s.samplerate, s.channels, s.hop_size\n" | ||
| 205 | "('movie.mp4', 16000, 1, 512)\n" | ||
| 206 | "\n" | ||
| 207 | "- open a remote resource, with hop_size = 1024:\n" | ||
| 208 | "\n" | ||
| 209 | ">>> s = aubio.source('https://aubio.org/drum.ogg', hop_size=1024)\n" | ||
| 210 | ">>> s.uri, s.samplerate, s.channels, s.hop_size\n" | ||
| 211 | "('https://aubio.org/drum.ogg', 48000, 2, 1024)\n" | ||
| 212 | "\n" | ||
| 213 | "See Also\n" | ||
| 214 | "--------\n" | ||
| 215 | "sink: write audio samples to a file.\n" | ||
| 216 | ""; | ||
| 51 | 217 | ||
| 52 | static char Py_source_get_samplerate_doc[] = "" | 218 | static char Py_source_get_samplerate_doc[] = "" |
| 53 | "x.get_samplerate() -> source samplerate\n" | 219 | "get_samplerate()\n" |
| 220 | "\n" | ||
| 221 | "Get sampling rate of source.\n" | ||
| 54 | "\n" | 222 | "\n" |
| 55 | "Get samplerate of source."; | 223 | "Returns\n" |
| 224 | "-------\n" | ||
| 225 | "int\n" | ||
| 226 | " Sampling rate, in Hz.\n" | ||
| 227 | ""; | ||
| 56 | 228 | ||
| 57 | static char Py_source_get_channels_doc[] = "" | 229 | static char Py_source_get_channels_doc[] = "" |
| 58 | "x.get_channels() -> number of channels\n" | 230 | "get_channels()\n" |
| 231 | "\n" | ||
| 232 | "Get number of channels in source.\n" | ||
| 59 | "\n" | 233 | "\n" |
| 60 | "Get number of channels in source."; | 234 | "Returns\n" |
| 235 | "-------\n" | ||
| 236 | "int\n" | ||
| 237 | " Number of channels.\n" | ||
| 238 | ""; | ||
| 61 | 239 | ||
| 62 | static char Py_source_do_doc[] = "" | 240 | static char Py_source_do_doc[] = "" |
| 63 | "vec, read = x.do() <==> vec, read = x()\n" | 241 | "source.do()\n" |
| 64 | "\n" | 242 | "\n" |
| 65 | "Read monophonic vector from source."; | 243 | "Read vector of audio samples.\n" |
| 244 | "\n" | ||
| 245 | "If the audio stream in the source has more than one channel,\n" | ||
| 246 | "the channels will be down-mixed.\n" | ||
| 247 | "\n" | ||
| 248 | "Returns\n" | ||
| 249 | "-------\n" | ||
| 250 | "samples : numpy.ndarray, shape `(hop_size,)`, dtype aubio.float_type\n" | ||
| 251 | " `fvec` of size `hop_size` containing the new samples.\n" | ||
| 252 | "read : int\n" | ||
| 253 | " Number of samples read from the source, equals to `hop_size`\n" | ||
| 254 | " before the end-of-file is reached, less when it is reached,\n" | ||
| 255 | " and `0` after.\n" | ||
| 256 | "\n" | ||
| 257 | "See Also\n" | ||
| 258 | "--------\n" | ||
| 259 | "do_multi\n" | ||
| 260 | "\n" | ||
| 261 | "Examples\n" | ||
| 262 | "--------\n" | ||
| 263 | ">>> src = aubio.source('sample.wav', hop_size=1024)\n" | ||
| 264 | ">>> src.do()\n" | ||
| 265 | "(array([-0.00123001, -0.00036685, 0.00097106, ..., -0.2031033 ,\n" | ||
| 266 | " -0.2025854 , -0.20221856], dtype=" AUBIO_NPY_SMPL_STR "), 1024)\n" | ||
| 267 | ""; | ||
| 66 | 268 | ||
| 67 | static char Py_source_do_multi_doc[] = "" | 269 | static char Py_source_do_multi_doc[] = "" |
| 68 | "mat, read = x.do_multi()\n" | 270 | "do_multi()\n" |
| 271 | "\n" | ||
| 272 | "Read multiple channels of audio samples.\n" | ||
| 273 | "\n" | ||
| 274 | "If the source was opened with the same number of channels\n" | ||
| 275 | "found in the stream, each channel will be read individually.\n" | ||
| 276 | "\n" | ||
| 277 | "If the source was opened with less channels than the number\n" | ||
| 278 | "of channels in the stream, only the first channels will be read.\n" | ||
| 69 | "\n" | 279 | "\n" |
| 70 | "Read polyphonic vector from source."; | 280 | "If the source was opened with more channels than the number\n" |
| 281 | "of channel in the original stream, the first channels will\n" | ||
| 282 | "be duplicated on the additional output channel.\n" | ||
| 283 | "\n" | ||
| 284 | "Returns\n" | ||
| 285 | "-------\n" | ||
| 286 | "samples : np.ndarray([hop_size, channels], dtype=aubio.float_type)\n" | ||
| 287 | " NumPy array of shape `(hop_size, channels)` containing the new\n" | ||
| 288 | " audio samples.\n" | ||
| 289 | "read : int\n" | ||
| 290 | " Number of samples read from the source, equals to `hop_size`\n" | ||
| 291 | " before the end-of-file is reached, less when it is reached,\n" | ||
| 292 | " and `0` after.\n" | ||
| 293 | "\n" | ||
| 294 | "See Also\n" | ||
| 295 | "--------\n" | ||
| 296 | "do\n" | ||
| 297 | "\n" | ||
| 298 | "Examples\n" | ||
| 299 | "--------\n" | ||
| 300 | ">>> src = aubio.source('sample.wav')\n" | ||
| 301 | ">>> src.do_multi()\n" | ||
| 302 | "(array([[ 0.00668335, 0.0067749 , 0.00714111, ..., -0.05737305,\n" | ||
| 303 | " -0.05856323, -0.06018066],\n" | ||
| 304 | " [-0.00842285, -0.0072937 , -0.00576782, ..., -0.09405518,\n" | ||
| 305 | " -0.09558105, -0.09725952]], dtype=" AUBIO_NPY_SMPL_STR "), 512)\n" | ||
| 306 | ""; | ||
| 71 | 307 | ||
| 72 | static char Py_source_close_doc[] = "" | 308 | static char Py_source_close_doc[] = "" |
| 73 | "x.close()\n" | 309 | "close()\n" |
| 74 | "\n" | 310 | "\n" |
| 75 | "Close this source now."; | 311 | "Close this source now.\n" |
| 312 | "\n" | ||
| 313 | ".. note:: Closing twice a source will **not** raise any exception.\n" | ||
| 314 | ""; | ||
| 76 | 315 | ||
| 77 | static char Py_source_seek_doc[] = "" | 316 | static char Py_source_seek_doc[] = "" |
| 78 | "x.seek(position)\n" | 317 | "seek(position)\n" |
| 318 | "\n" | ||
| 319 | "Seek to position in file.\n" | ||
| 320 | "\n" | ||
| 321 | "If the source was not opened with its original sampling-rate,\n" | ||
| 322 | "`position` corresponds to the position in the re-sampled file.\n" | ||
| 79 | "\n" | 323 | "\n" |
| 80 | "Seek to resampled frame position."; | 324 | "Parameters\n" |
| 325 | "----------\n" | ||
| 326 | "position : str\n" | ||
| 327 | " position to seek to, in samples\n" | ||
| 328 | ""; | ||
| 81 | 329 | ||
| 82 | static PyObject * | 330 | static PyObject * |
| 83 | Py_source_new (PyTypeObject * pytype, PyObject * args, PyObject * kwds) | 331 | Py_source_new (PyTypeObject * pytype, PyObject * args, PyObject * kwds) |
| @@ -217,15 +465,29 @@ Py_source_do_multi(Py_source * self, PyObject * args) · 133 unmodified lines | |||
| 217 | 465 | ||
| 218 | static PyMemberDef Py_source_members[] = { | 466 | static PyMemberDef Py_source_members[] = { |
| 219 | {"uri", T_STRING, offsetof (Py_source, uri), READONLY, | 467 | {"uri", T_STRING, offsetof (Py_source, uri), READONLY, |
| 220 | "path at which the source was created"}, | 468 | "str (read-only): pathname or URL"}, |
| 221 | {"samplerate", T_INT, offsetof (Py_source, samplerate), READONLY, | 469 | {"samplerate", T_INT, offsetof (Py_source, samplerate), READONLY, |
| 222 | "samplerate at which the source is viewed"}, | 470 | "int (read-only): sampling rate"}, |
| 223 | {"channels", T_INT, offsetof (Py_source, channels), READONLY, | 471 | {"channels", T_INT, offsetof (Py_source, channels), READONLY, |
| 224 | "number of channels found in the source"}, | 472 | "int (read-only): number of channels"}, |
| 225 | {"hop_size", T_INT, offsetof (Py_source, hop_size), READONLY, | 473 | {"hop_size", T_INT, offsetof (Py_source, hop_size), READONLY, |
| 226 | "number of consecutive frames that will be read at each do or do_multi call"}, | 474 | "int (read-only): number of samples read per iteration"}, |
| 227 | {"duration", T_INT, offsetof (Py_source, duration), READONLY, | 475 | {"duration", T_INT, offsetof (Py_source, duration), READONLY, |
| 228 | "total number of frames in the source (estimated)"}, | 476 | "int (read-only): total number of frames in the source\n" |
| 477 | "\n" | ||
| 478 | "Can be estimated, for instance if the opened stream is\n" | ||
| 479 | "a compressed media or a remote resource.\n" | ||
| 480 | "\n" | ||
| 481 | "Example\n" | ||
| 482 | "-------\n" | ||
| 483 | ">>> n = 0\n" | ||
| 484 | ">>> src = aubio.source('track1.mp3')\n" | ||
| 485 | ">>> for samples in src:\n" | ||
| 486 | "... n += samples.shape[-1]\n" | ||
| 487 | "...\n" | ||
| 488 | ">>> n, src.duration\n" | ||
| 489 | "(9638784, 9616561)\n" | ||
| 490 | ""}, | ||
| 229 | { NULL } // sentinel | 491 | { NULL } // sentinel |
| 230 | }; | 492 | }; |
| 231 | 493 | ||