diff options
| author | CoprDistGit <infra@openeuler.org> | 2023-04-11 18:00:56 +0000 |
|---|---|---|
| committer | CoprDistGit <infra@openeuler.org> | 2023-04-11 18:00:56 +0000 |
| commit | cd5f9fcdb6e8fc4b9cad7ce1420059ae5048f1da (patch) | |
| tree | b18f18f5c711eaaa15b46f31ff8646f7c24d4f4f | |
| parent | 80fee6adc00f956edf4507c4f4b57272f8107f91 (diff) | |
automatic import of python-miniaudio
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | python-miniaudio.spec | 1585 | ||||
| -rw-r--r-- | sources | 1 |
3 files changed, 1587 insertions, 0 deletions
@@ -0,0 +1 @@ +/miniaudio-1.56.tar.gz diff --git a/python-miniaudio.spec b/python-miniaudio.spec new file mode 100644 index 0000000..ac9d8a2 --- /dev/null +++ b/python-miniaudio.spec @@ -0,0 +1,1585 @@ +%global _empty_manifest_terminate_build 0 +Name: python-miniaudio +Version: 1.56 +Release: 1 +Summary: python bindings for the miniaudio library and its decoders (mp3, flac, ogg vorbis, wav) +License: MIT +URL: https://github.com/irmen/pyminiaudio +Source0: https://mirrors.nju.edu.cn/pypi/web/packages/19/3a/823b071af23998231047c899184ecc47bc5d757a1df78f05e76bc0fea721/miniaudio-1.56.tar.gz + +Requires: python3-cffi +Requires: python3-wheel + +%description +[](https://pypi.python.org/pypi/miniaudio/) + + +# Python miniaudio + +Multiplatform audio playback, recording, decoding and sample format conversion for +Linux (including Raspberri Pi), Windows, Mac and others. + +Installation for most users: via [Pypi](https://pypi.org/project/miniaudio/), Raspberri Pi builds via [PiWheels](https://www.piwheels.org/project/miniaudio/). + + +This is a Pythonic interface to the cross-platform [miniaudio](https://github.com/dr-soft/miniaudio/) C library: + +- audio operations run in the background +- python bindings for most of the functions offered in the miniaudio library: + - reading and decoding audio files + - getting audio file properties (such as duration, number of channels, sample rate) + - converting sample formats and frequencies + - streaming large audio files + - audio playback + - audio recording +- decoders for wav, flac, vorbis and mp3 +- Audio file and Icecast internet radio streaming +- Python enums instead of just some integers for special values +- several classes to represent the main functions of the library +- generators for the Audio playback and recording +- sample data is usually in the form of a Python ``array`` with appropriately sized elements + depending on the sample width (rather than a raw block of bytes) +- TODO: filters, waveform generators? + + +*Requires Python 3.6 or newer. Also works on pypy3 (because it uses cffi).* + +Software license for these Python bindings, miniaudio and the decoders: MIT + +## Synthesizer, modplayer? + +If you like this library you may also be interested in my [software FM synthesizer](https://pypi.org/project/synthplayer/) +or my [mod player](https://pypi.org/project/libxmplite/) which uses libxmp. + + +## Examples + +### Most basic audio file playback + +```python +import miniaudio +stream = miniaudio.stream_file("samples/music.mp3") +with miniaudio.PlaybackDevice() as device: + device.start(stream) + input("Audio file playing in the background. Enter to stop playback: ") +``` + +### Playback of an unsupported file format + +This example uses ffmpeg as an external tool to decode an audio file in a format +that miniaudio itself can't decode (m4a/aac in this case): + +```python +import subprocess +import miniaudio + +channels = 2 +sample_rate = 44100 +sample_width = 2 # 16 bit pcm +filename = "samples/music.m4a" # AAC encoded audio file + +def stream_pcm(source): + required_frames = yield b"" # generator initialization + while True: + required_bytes = required_frames * channels * sample_width + sample_data = source.read(required_bytes) + if not sample_data: + break + print(".", end="", flush=True) + required_frames = yield sample_data + +with miniaudio.PlaybackDevice(output_format=miniaudio.SampleFormat.SIGNED16, + nchannels=channels, sample_rate=sample_rate) as device: + ffmpeg = subprocess.Popen(["ffmpeg", "-v", "fatal", "-hide_banner", "-nostdin", + "-i", filename, "-f", "s16le", "-acodec", "pcm_s16le", + "-ac", str(channels), "-ar", str(sample_rate), "-"], + stdin=None, stdout=subprocess.PIPE) + stream = stream_pcm(ffmpeg.stdout) + next(stream) # start the generator + device.start(stream) + input("Audio file playing in the background. Enter to stop playback: ") + ffmpeg.terminate() +``` + +## API + +### Note: everything below is automatically generated from comments in the source code files. Do not edit in this readme directly. + +*enum class* ``Backend`` + names: ``WASAPI`` ``DSOUND`` ``WINMM`` ``COREAUDIO`` ``SNDIO`` ``AUDIO4`` ``OSS`` ``PULSEAUDIO`` ``ALSA`` ``JACK`` ``AAUDIO`` ``OPENSL`` ``WEBAUDIO`` ``CUSTOM`` ``NULL`` +> Operating system audio backend to use (only a subset will be available) + + +*enum class* ``ChannelMixMode`` + names: ``RECTANGULAR`` ``SIMPLE`` ``CUSTOMWEIGHTS`` +> How to mix channels when converting + + +*enum class* ``DeviceType`` + names: ``PLAYBACK`` ``CAPTURE`` ``DUPLEX`` +> Type of audio device + + +*enum class* ``DitherMode`` + names: ``NONE`` ``RECTANGLE`` ``TRIANGLE`` +> How to dither when converting + + +*enum class* ``FileFormat`` + names: ``UNKNOWN`` ``WAV`` ``FLAC`` ``MP3`` ``VORBIS`` +> Audio file format + + +*enum class* ``SampleFormat`` + names: ``UNKNOWN`` ``UNSIGNED8`` ``SIGNED16`` ``SIGNED24`` ``SIGNED32`` ``FLOAT32`` +> Sample format in memory + + +*enum class* ``SeekOrigin`` + names: ``START`` ``CURRENT`` +> How to seek() in a source + + +*enum class* ``ThreadPriority`` + names: ``IDLE`` ``LOWEST`` ``LOW`` ``NORMAL`` ``HIGH`` ``HIGHEST`` ``REALTIME`` +> The priority of the worker thread (default=HIGHEST) + + +*function* ``convert_frames (from_fmt: miniaudio.SampleFormat, from_numchannels: int, from_samplerate: int, sourcedata: bytes, to_fmt: miniaudio.SampleFormat, to_numchannels: int, to_samplerate: int) -> bytearray`` +> Convert audio frames in source sample format with a certain number of channels, to another sample +format and possibly down/upmixing the number of channels as well. + + +*function* ``convert_sample_format (from_fmt: miniaudio.SampleFormat, sourcedata: bytes, to_fmt: miniaudio.SampleFormat, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>) -> bytearray`` +> Convert a raw buffer of pcm samples to another sample format. The result is returned as another +raw pcm sample buffer + + +*function* ``decode (data: bytes, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>) -> miniaudio.DecodedSoundFile`` +> Convenience function to decode any supported audio file in memory to raw PCM samples in your +chosen format. + + +*function* ``decode_file (filename: str, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>) -> miniaudio.DecodedSoundFile`` +> Convenience function to decode any supported audio file to raw PCM samples in your chosen format. + + +*function* ``flac_get_file_info (filename: str) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio file (flac format). + + +*function* ``flac_get_info (data: bytes) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio data (flac format). + + +*function* ``flac_read_f32 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole flac audio file. Resulting sample format is 32 bits float. + + +*function* ``flac_read_file_f32 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole flac audio file. Resulting sample format is 32 bits float. + + +*function* ``flac_read_file_s16 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole flac audio file. Resulting sample format is 16 bits signed integer. + + +*function* ``flac_read_file_s32 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole flac audio file. Resulting sample format is 32 bits signed integer. + + +*function* ``flac_read_s16 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole flac audio data. Resulting sample format is 16 bits signed integer. + + +*function* ``flac_read_s32 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole flac audio data. Resulting sample format is 32 bits signed integer. + + +*function* ``flac_stream_file (filename: str, frames_to_read: int = 1024, seek_frame: int = 0) -> Generator[array.array, NoneType, NoneType]`` +> Streams the flac audio file as interleaved 16 bit signed integer sample arrays segments. This uses +a fixed chunk size and cannot be used as a generic miniaudio decoder input stream. Consider using +stream_file() instead. + + +*function* ``get_enabled_backends () -> Set[miniaudio.Backend]`` +> Returns the set of available backends by the compilation environment for the underlying miniaudio +C library + + +*function* ``get_file_info (filename: str) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio file. + + +*function* ``is_backend_enabled (backend: miniaudio.Backend) -> bool`` +> Determines whether or not the given backend is available by the compilation environment for the +underlying miniaudio C library + + +*function* ``is_loopback_supported (backend: miniaudio.Backend) -> bool`` +> Determines whether or not loopback mode is support by a backend. + + +*function* ``lib_version () -> str`` +> Returns the version string of the underlying miniaudio C library + + +*function* ``mp3_get_file_info (filename: str) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio file (mp3 format). + + +*function* ``mp3_get_info (data: bytes) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio data (mp3 format). + + +*function* ``mp3_read_f32 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole mp3 audio data. Resulting sample format is 32 bits float. + + +*function* ``mp3_read_file_f32 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole mp3 audio file. Resulting sample format is 32 bits float. + + +*function* ``mp3_read_file_s16 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole mp3 audio file. Resulting sample format is 16 bits signed integer. + + +*function* ``mp3_read_s16 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole mp3 audio data. Resulting sample format is 16 bits signed integer. + + +*function* ``mp3_stream_file (filename: str, frames_to_read: int = 1024, seek_frame: int = 0) -> Generator[array.array, NoneType, NoneType]`` +> Streams the mp3 audio file as interleaved 16 bit signed integer sample arrays segments. This uses +a fixed chunk size and cannot be used as a generic miniaudio decoder input stream. Consider using +stream_file() instead. + + +*function* ``read_file (filename: str, convert_to_16bit: bool = False) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole audio file. Miniaudio will attempt to return the sound data in exactly +the same format as in the file. Unless you set convert_convert_to_16bit to True, then the result is +always a 16 bit sample format. + + +*function* ``stream_any (source: miniaudio.StreamableSource, source_format: miniaudio.FileFormat = <FileFormat.UNKNOWN: 0>, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, frames_to_read: int = 1024, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>, seek_frame: int = 0) -> Generator[array.array, int, NoneType]`` +> Convenience function that returns a generator to decode and stream any source of encoded audio +data (such as a network stream). Stream result is chunks of raw PCM samples in the chosen format. If +you send() a number into the generator rather than just using next() on it, you'll get that given +number of frames, instead of the default configured amount. This is particularly useful to plug this +stream into an audio device callback that wants a variable number of frames per call. + + +*function* ``stream_file (filename: str, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, frames_to_read: int = 1024, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>, seek_frame: int = 0) -> Generator[array.array, int, NoneType]`` +> Convenience generator function to decode and stream any supported audio file as chunks of raw PCM +samples in the chosen format. If you send() a number into the generator rather than just using +next() on it, you'll get that given number of frames, instead of the default configured amount. This +is particularly useful to plug this stream into an audio device callback that wants a variable +number of frames per call. + + +*function* ``stream_memory (data: bytes, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, frames_to_read: int = 1024, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>) -> Generator[array.array, int, NoneType]`` +> Convenience generator function to decode and stream any supported audio file in memory as chunks +of raw PCM samples in the chosen format. If you send() a number into the generator rather than just +using next() on it, you'll get that given number of frames, instead of the default configured +amount. This is particularly useful to plug this stream into an audio device callback that wants a +variable number of frames per call. + + +*function* ``stream_raw_pcm_memory (pcmdata: Union[array.array, memoryview, bytes], nchannels: int, sample_width: int, frames_to_read: int = 4096) -> Generator[Union[bytes, array.array], int, NoneType]`` +> Convenience generator function to stream raw pcm audio data from memory. Usually you don't need to +use this as the library provides many other streaming options that work on much smaller, encoded, +audio data. However, in the odd case that you only have already decoded raw pcm data you can use +this generator as a stream source. The data can be provided in ``array`` type or ``bytes``, +``memoryview`` or even a numpy array. Be sure to also specify the correct number of channels that +the audio data has, and the sample with in bytes. + + +*function* ``stream_with_callbacks (sample_stream: Generator[Union[bytes, array.array], int, NoneType], progress_callback: Optional[Callable[[int], NoneType]] = None, frame_process_method: Optional[Callable[[Union[bytes, array.array]], Union[bytes, array.array]]] = None, end_callback: Optional[Callable] = None) -> Generator[Union[bytes, array.array], int, NoneType]`` +> Convenience generator function to add callback and processing functionality to another stream. You +can specify : > A callback function that gets called during play and takes an int for the number of +frames played. > A function that can be used to process raw data frames before they are yielded +back (takes an array.array or bytes, returns an array.array or bytes) *Note: if the processing +method is slow it will result in audio glitchiness > A callback function that gets called when the +stream ends playing. + + +*function* ``vorbis_get_file_info (filename: str) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio file (vorbis format). + + +*function* ``vorbis_get_info (data: bytes) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio data (vorbis format). + + +*function* ``vorbis_read (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole vorbis audio data. Resulting sample format is 16 bits signed integer. + + +*function* ``vorbis_read_file (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole vorbis audio file. Resulting sample format is 16 bits signed integer. + + +*function* ``vorbis_stream_file (filename: str, seek_frame: int = 0) -> Generator[array.array, NoneType, NoneType]`` +> Streams the ogg vorbis audio file as interleaved 16 bit signed integer sample arrays segments. +This uses a variable unconfigurable chunk size and cannot be used as a generic miniaudio decoder +input stream. Consider using stream_file() instead. + + +*function* ``wav_get_file_info (filename: str) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio file (wav format). + + +*function* ``wav_get_info (data: bytes) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio data (wav format). + + +*function* ``wav_read_f32 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole wav audio data. Resulting sample format is 32 bits float. + + +*function* ``wav_read_file_f32 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole wav audio file. Resulting sample format is 32 bits float. + + +*function* ``wav_read_file_s16 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole wav audio file. Resulting sample format is 16 bits signed integer. + + +*function* ``wav_read_file_s32 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole wav audio file. Resulting sample format is 32 bits signed integer. + + +*function* ``wav_read_s16 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole wav audio data. Resulting sample format is 16 bits signed integer. + + +*function* ``wav_read_s32 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole wav audio data. Resulting sample format is 32 bits signed integer. + + +*function* ``wav_stream_file (filename: str, frames_to_read: int = 1024, seek_frame: int = 0) -> Generator[array.array, NoneType, NoneType]`` +> Streams the WAV audio file as interleaved 16 bit signed integer sample arrays segments. This uses +a fixed chunk size and cannot be used as a generic miniaudio decoder input stream. Consider using +stream_file() instead. + + +*function* ``wav_write_file (filename: str, sound: miniaudio.DecodedSoundFile) `` +> Writes the pcm sound to a WAV file + + +*function* ``width_from_format (sampleformat: miniaudio.SampleFormat) -> int`` +> returns the sample width in bytes, of the given sample format. + + +*class* ``CaptureDevice`` + +``CaptureDevice (self, input_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, buffersize_msec: int = 200, device_id: Optional[_cffi_backend._CDataBase] = None, callback_periods: int = 0, backends: Optional[List[miniaudio.Backend]] = None, thread_prio: miniaudio.ThreadPriority = <ThreadPriority.HIGHEST: 0>, app_name: str = '') `` +> An audio device provided by miniaudio, for audio capture (recording). + +> *method* ``close (self) `` +> > Halt playback or capture and close down the device. If you use the device as a context manager, +it will be closed automatically. + +> *method* ``start (self, callback_generator: Generator[NoneType, Union[bytes, array.array], NoneType]) `` +> > Start the audio device: capture (recording) begins. The recorded audio data is sent to the given +callback generator as raw bytes. (it should already be started before) + +> *method* ``stop (self) `` +> > Halt playback or capture. + + +*class* ``DecodeError`` + +``DecodeError (self, /, *args, **kwargs)`` +> When something went wrong during decoding an audio file. + + +*class* ``DecodedSoundFile`` + +``DecodedSoundFile (self, name: str, nchannels: int, sample_rate: int, sample_format: miniaudio.SampleFormat, samples: array.array) `` +> Contains various properties and also the PCM frames of a fully decoded audio file. + + +*class* ``Devices`` + +``Devices (self, backends: Optional[List[miniaudio.Backend]] = None) `` +> Query the audio playback and record devices that miniaudio provides + +> *method* ``get_captures (self) -> List[Dict[str, Any]]`` +> > Get a list of capture devices and some details about them + +> *method* ``get_playbacks (self) -> List[Dict[str, Any]]`` +> > Get a list of playback devices and some details about them + + +*class* ``DuplexStream`` + +``DuplexStream (self, playback_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, playback_channels: int = 2, capture_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, capture_channels: int = 2, sample_rate: int = 44100, buffersize_msec: int = 200, playback_device_id: Optional[_cffi_backend._CDataBase] = None, capture_device_id: Optional[_cffi_backend._CDataBase] = None, callback_periods: int = 0, backends: Optional[List[miniaudio.Backend]] = None, thread_prio: miniaudio.ThreadPriority = <ThreadPriority.HIGHEST: 0>, app_name: str = '') `` +> Joins a capture device and a playback device. + +> *method* ``close (self) `` +> > Halt playback or capture and close down the device. If you use the device as a context manager, +it will be closed automatically. + +> *method* ``start (self, callback_generator: Generator[Union[bytes, array.array], Union[bytes, array.array], NoneType]) `` +> > Start the audio device: playback and capture begin. The audio data for playback is provided by +the given callback generator, which is sent the recorded audio data at the same time. (it should +already be started before passing it in) + +> *method* ``stop (self) `` +> > Halt playback or capture. + + +*class* ``IceCastClient`` + +``IceCastClient (self, url: str, update_stream_title: Callable[[ForwardRef('IceCastClient'), str], NoneType] = None, ssl_context: 'ssl.SSLContext' = None) `` +> A simple client for IceCast audio streams as miniaudio streamable source. If the stream has Icy +MetaData, the stream_title attribute will be updated with the actual title taken from the metadata. +You can also provide a callback to be called when a new stream title is available. The downloading +of the data from the internet is done in a background thread and it tries to keep a (small) buffer +filled with available data to read. You can optionally provide a custom ssl.SSLContext in the +ssl_context parameter, if you need to change the way SSL connections are configured (certificates, +checks, etc). + +> *method* ``close (self) `` +> > Stop the stream, aborting the background downloading. + +> *method* ``read (self, num_bytes: int) -> bytes`` +> > Read a chunk of data from the stream. + +> *method* ``seek (self, offset: int, origin: miniaudio.SeekOrigin) -> bool`` +> > Override this if the stream supports seeking. Note: seek support is sometimes not needed if you +give the file type to a decoder upfront. You can ignore this method then. + + +*class* ``MiniaudioError`` + +``MiniaudioError (self, /, *args, **kwargs)`` +> When a miniaudio specific error occurs. + + +*class* ``PlaybackDevice`` + +``PlaybackDevice (self, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, buffersize_msec: int = 200, device_id: Optional[_cffi_backend._CDataBase] = None, callback_periods: int = 0, backends: Optional[List[miniaudio.Backend]] = None, thread_prio: miniaudio.ThreadPriority = <ThreadPriority.HIGHEST: 0>, app_name: str = '') `` +> An audio device provided by miniaudio, for audio playback. + +> *method* ``close (self) `` +> > Halt playback or capture and close down the device. If you use the device as a context manager, +it will be closed automatically. + +> *method* ``start (self, callback_generator: Generator[Union[bytes, array.array], int, NoneType]) `` +> > Start the audio device: playback begins. The audio data is provided by the given callback +generator. The generator gets sent the required number of frames and should yield the sample data as +raw bytes, a memoryview, an array.array, or as a numpy array with shape (numframes, numchannels). +The generator should already be started before passing it in. + +> *method* ``stop (self) `` +> > Halt playback or capture. + + +*class* ``SoundFileInfo`` + +``SoundFileInfo (self, name: str, file_format: miniaudio.FileFormat, nchannels: int, sample_rate: int, sample_format: miniaudio.SampleFormat, duration: float, num_frames: int, sub_format: int = None) `` +> Contains various properties of an audio file. + + +*class* ``StreamableSource`` + +``StreamableSource (self, /, *args, **kwargs)`` +> Base class for streams of audio data bytes. Can be used as a contextmanager, to properly call +close(). + +> *method* ``close (self) `` +> > Override this to properly close the stream and free resources. + +> *method* ``read (self, num_bytes: int) -> Union[bytes, memoryview]`` +> > override this to provide data bytes to the consumer of the stream + +> *method* ``seek (self, offset: int, origin: miniaudio.SeekOrigin) -> bool`` +> > Override this if the stream supports seeking. Note: seek support is sometimes not needed if you +give the file type to a decoder upfront. You can ignore this method then. + + +*class* ``WavFileReadStream`` + +``WavFileReadStream (self, pcm_sample_gen: Generator[Union[bytes, array.array], int, NoneType], sample_rate: int, nchannels: int, output_format: miniaudio.SampleFormat, max_frames: int = 0) `` +> An IO stream that reads as a .wav file, and which gets its pcm samples from the provided producer + +> *method* ``close (self) `` +> > Close the file + +> *method* ``read (self, amount: int = 9223372036854775807) -> Optional[bytes]`` +> > Read up to the given amount of bytes from the file. + + + + + + + +%package -n python3-miniaudio +Summary: python bindings for the miniaudio library and its decoders (mp3, flac, ogg vorbis, wav) +Provides: python-miniaudio +BuildRequires: python3-devel +BuildRequires: python3-setuptools +BuildRequires: python3-pip +BuildRequires: python3-cffi +BuildRequires: gcc +BuildRequires: gdb +%description -n python3-miniaudio +[](https://pypi.python.org/pypi/miniaudio/) + + +# Python miniaudio + +Multiplatform audio playback, recording, decoding and sample format conversion for +Linux (including Raspberri Pi), Windows, Mac and others. + +Installation for most users: via [Pypi](https://pypi.org/project/miniaudio/), Raspberri Pi builds via [PiWheels](https://www.piwheels.org/project/miniaudio/). + + +This is a Pythonic interface to the cross-platform [miniaudio](https://github.com/dr-soft/miniaudio/) C library: + +- audio operations run in the background +- python bindings for most of the functions offered in the miniaudio library: + - reading and decoding audio files + - getting audio file properties (such as duration, number of channels, sample rate) + - converting sample formats and frequencies + - streaming large audio files + - audio playback + - audio recording +- decoders for wav, flac, vorbis and mp3 +- Audio file and Icecast internet radio streaming +- Python enums instead of just some integers for special values +- several classes to represent the main functions of the library +- generators for the Audio playback and recording +- sample data is usually in the form of a Python ``array`` with appropriately sized elements + depending on the sample width (rather than a raw block of bytes) +- TODO: filters, waveform generators? + + +*Requires Python 3.6 or newer. Also works on pypy3 (because it uses cffi).* + +Software license for these Python bindings, miniaudio and the decoders: MIT + +## Synthesizer, modplayer? + +If you like this library you may also be interested in my [software FM synthesizer](https://pypi.org/project/synthplayer/) +or my [mod player](https://pypi.org/project/libxmplite/) which uses libxmp. + + +## Examples + +### Most basic audio file playback + +```python +import miniaudio +stream = miniaudio.stream_file("samples/music.mp3") +with miniaudio.PlaybackDevice() as device: + device.start(stream) + input("Audio file playing in the background. Enter to stop playback: ") +``` + +### Playback of an unsupported file format + +This example uses ffmpeg as an external tool to decode an audio file in a format +that miniaudio itself can't decode (m4a/aac in this case): + +```python +import subprocess +import miniaudio + +channels = 2 +sample_rate = 44100 +sample_width = 2 # 16 bit pcm +filename = "samples/music.m4a" # AAC encoded audio file + +def stream_pcm(source): + required_frames = yield b"" # generator initialization + while True: + required_bytes = required_frames * channels * sample_width + sample_data = source.read(required_bytes) + if not sample_data: + break + print(".", end="", flush=True) + required_frames = yield sample_data + +with miniaudio.PlaybackDevice(output_format=miniaudio.SampleFormat.SIGNED16, + nchannels=channels, sample_rate=sample_rate) as device: + ffmpeg = subprocess.Popen(["ffmpeg", "-v", "fatal", "-hide_banner", "-nostdin", + "-i", filename, "-f", "s16le", "-acodec", "pcm_s16le", + "-ac", str(channels), "-ar", str(sample_rate), "-"], + stdin=None, stdout=subprocess.PIPE) + stream = stream_pcm(ffmpeg.stdout) + next(stream) # start the generator + device.start(stream) + input("Audio file playing in the background. Enter to stop playback: ") + ffmpeg.terminate() +``` + +## API + +### Note: everything below is automatically generated from comments in the source code files. Do not edit in this readme directly. + +*enum class* ``Backend`` + names: ``WASAPI`` ``DSOUND`` ``WINMM`` ``COREAUDIO`` ``SNDIO`` ``AUDIO4`` ``OSS`` ``PULSEAUDIO`` ``ALSA`` ``JACK`` ``AAUDIO`` ``OPENSL`` ``WEBAUDIO`` ``CUSTOM`` ``NULL`` +> Operating system audio backend to use (only a subset will be available) + + +*enum class* ``ChannelMixMode`` + names: ``RECTANGULAR`` ``SIMPLE`` ``CUSTOMWEIGHTS`` +> How to mix channels when converting + + +*enum class* ``DeviceType`` + names: ``PLAYBACK`` ``CAPTURE`` ``DUPLEX`` +> Type of audio device + + +*enum class* ``DitherMode`` + names: ``NONE`` ``RECTANGLE`` ``TRIANGLE`` +> How to dither when converting + + +*enum class* ``FileFormat`` + names: ``UNKNOWN`` ``WAV`` ``FLAC`` ``MP3`` ``VORBIS`` +> Audio file format + + +*enum class* ``SampleFormat`` + names: ``UNKNOWN`` ``UNSIGNED8`` ``SIGNED16`` ``SIGNED24`` ``SIGNED32`` ``FLOAT32`` +> Sample format in memory + + +*enum class* ``SeekOrigin`` + names: ``START`` ``CURRENT`` +> How to seek() in a source + + +*enum class* ``ThreadPriority`` + names: ``IDLE`` ``LOWEST`` ``LOW`` ``NORMAL`` ``HIGH`` ``HIGHEST`` ``REALTIME`` +> The priority of the worker thread (default=HIGHEST) + + +*function* ``convert_frames (from_fmt: miniaudio.SampleFormat, from_numchannels: int, from_samplerate: int, sourcedata: bytes, to_fmt: miniaudio.SampleFormat, to_numchannels: int, to_samplerate: int) -> bytearray`` +> Convert audio frames in source sample format with a certain number of channels, to another sample +format and possibly down/upmixing the number of channels as well. + + +*function* ``convert_sample_format (from_fmt: miniaudio.SampleFormat, sourcedata: bytes, to_fmt: miniaudio.SampleFormat, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>) -> bytearray`` +> Convert a raw buffer of pcm samples to another sample format. The result is returned as another +raw pcm sample buffer + + +*function* ``decode (data: bytes, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>) -> miniaudio.DecodedSoundFile`` +> Convenience function to decode any supported audio file in memory to raw PCM samples in your +chosen format. + + +*function* ``decode_file (filename: str, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>) -> miniaudio.DecodedSoundFile`` +> Convenience function to decode any supported audio file to raw PCM samples in your chosen format. + + +*function* ``flac_get_file_info (filename: str) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio file (flac format). + + +*function* ``flac_get_info (data: bytes) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio data (flac format). + + +*function* ``flac_read_f32 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole flac audio file. Resulting sample format is 32 bits float. + + +*function* ``flac_read_file_f32 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole flac audio file. Resulting sample format is 32 bits float. + + +*function* ``flac_read_file_s16 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole flac audio file. Resulting sample format is 16 bits signed integer. + + +*function* ``flac_read_file_s32 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole flac audio file. Resulting sample format is 32 bits signed integer. + + +*function* ``flac_read_s16 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole flac audio data. Resulting sample format is 16 bits signed integer. + + +*function* ``flac_read_s32 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole flac audio data. Resulting sample format is 32 bits signed integer. + + +*function* ``flac_stream_file (filename: str, frames_to_read: int = 1024, seek_frame: int = 0) -> Generator[array.array, NoneType, NoneType]`` +> Streams the flac audio file as interleaved 16 bit signed integer sample arrays segments. This uses +a fixed chunk size and cannot be used as a generic miniaudio decoder input stream. Consider using +stream_file() instead. + + +*function* ``get_enabled_backends () -> Set[miniaudio.Backend]`` +> Returns the set of available backends by the compilation environment for the underlying miniaudio +C library + + +*function* ``get_file_info (filename: str) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio file. + + +*function* ``is_backend_enabled (backend: miniaudio.Backend) -> bool`` +> Determines whether or not the given backend is available by the compilation environment for the +underlying miniaudio C library + + +*function* ``is_loopback_supported (backend: miniaudio.Backend) -> bool`` +> Determines whether or not loopback mode is support by a backend. + + +*function* ``lib_version () -> str`` +> Returns the version string of the underlying miniaudio C library + + +*function* ``mp3_get_file_info (filename: str) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio file (mp3 format). + + +*function* ``mp3_get_info (data: bytes) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio data (mp3 format). + + +*function* ``mp3_read_f32 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole mp3 audio data. Resulting sample format is 32 bits float. + + +*function* ``mp3_read_file_f32 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole mp3 audio file. Resulting sample format is 32 bits float. + + +*function* ``mp3_read_file_s16 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole mp3 audio file. Resulting sample format is 16 bits signed integer. + + +*function* ``mp3_read_s16 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole mp3 audio data. Resulting sample format is 16 bits signed integer. + + +*function* ``mp3_stream_file (filename: str, frames_to_read: int = 1024, seek_frame: int = 0) -> Generator[array.array, NoneType, NoneType]`` +> Streams the mp3 audio file as interleaved 16 bit signed integer sample arrays segments. This uses +a fixed chunk size and cannot be used as a generic miniaudio decoder input stream. Consider using +stream_file() instead. + + +*function* ``read_file (filename: str, convert_to_16bit: bool = False) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole audio file. Miniaudio will attempt to return the sound data in exactly +the same format as in the file. Unless you set convert_convert_to_16bit to True, then the result is +always a 16 bit sample format. + + +*function* ``stream_any (source: miniaudio.StreamableSource, source_format: miniaudio.FileFormat = <FileFormat.UNKNOWN: 0>, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, frames_to_read: int = 1024, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>, seek_frame: int = 0) -> Generator[array.array, int, NoneType]`` +> Convenience function that returns a generator to decode and stream any source of encoded audio +data (such as a network stream). Stream result is chunks of raw PCM samples in the chosen format. If +you send() a number into the generator rather than just using next() on it, you'll get that given +number of frames, instead of the default configured amount. This is particularly useful to plug this +stream into an audio device callback that wants a variable number of frames per call. + + +*function* ``stream_file (filename: str, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, frames_to_read: int = 1024, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>, seek_frame: int = 0) -> Generator[array.array, int, NoneType]`` +> Convenience generator function to decode and stream any supported audio file as chunks of raw PCM +samples in the chosen format. If you send() a number into the generator rather than just using +next() on it, you'll get that given number of frames, instead of the default configured amount. This +is particularly useful to plug this stream into an audio device callback that wants a variable +number of frames per call. + + +*function* ``stream_memory (data: bytes, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, frames_to_read: int = 1024, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>) -> Generator[array.array, int, NoneType]`` +> Convenience generator function to decode and stream any supported audio file in memory as chunks +of raw PCM samples in the chosen format. If you send() a number into the generator rather than just +using next() on it, you'll get that given number of frames, instead of the default configured +amount. This is particularly useful to plug this stream into an audio device callback that wants a +variable number of frames per call. + + +*function* ``stream_raw_pcm_memory (pcmdata: Union[array.array, memoryview, bytes], nchannels: int, sample_width: int, frames_to_read: int = 4096) -> Generator[Union[bytes, array.array], int, NoneType]`` +> Convenience generator function to stream raw pcm audio data from memory. Usually you don't need to +use this as the library provides many other streaming options that work on much smaller, encoded, +audio data. However, in the odd case that you only have already decoded raw pcm data you can use +this generator as a stream source. The data can be provided in ``array`` type or ``bytes``, +``memoryview`` or even a numpy array. Be sure to also specify the correct number of channels that +the audio data has, and the sample with in bytes. + + +*function* ``stream_with_callbacks (sample_stream: Generator[Union[bytes, array.array], int, NoneType], progress_callback: Optional[Callable[[int], NoneType]] = None, frame_process_method: Optional[Callable[[Union[bytes, array.array]], Union[bytes, array.array]]] = None, end_callback: Optional[Callable] = None) -> Generator[Union[bytes, array.array], int, NoneType]`` +> Convenience generator function to add callback and processing functionality to another stream. You +can specify : > A callback function that gets called during play and takes an int for the number of +frames played. > A function that can be used to process raw data frames before they are yielded +back (takes an array.array or bytes, returns an array.array or bytes) *Note: if the processing +method is slow it will result in audio glitchiness > A callback function that gets called when the +stream ends playing. + + +*function* ``vorbis_get_file_info (filename: str) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio file (vorbis format). + + +*function* ``vorbis_get_info (data: bytes) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio data (vorbis format). + + +*function* ``vorbis_read (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole vorbis audio data. Resulting sample format is 16 bits signed integer. + + +*function* ``vorbis_read_file (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole vorbis audio file. Resulting sample format is 16 bits signed integer. + + +*function* ``vorbis_stream_file (filename: str, seek_frame: int = 0) -> Generator[array.array, NoneType, NoneType]`` +> Streams the ogg vorbis audio file as interleaved 16 bit signed integer sample arrays segments. +This uses a variable unconfigurable chunk size and cannot be used as a generic miniaudio decoder +input stream. Consider using stream_file() instead. + + +*function* ``wav_get_file_info (filename: str) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio file (wav format). + + +*function* ``wav_get_info (data: bytes) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio data (wav format). + + +*function* ``wav_read_f32 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole wav audio data. Resulting sample format is 32 bits float. + + +*function* ``wav_read_file_f32 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole wav audio file. Resulting sample format is 32 bits float. + + +*function* ``wav_read_file_s16 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole wav audio file. Resulting sample format is 16 bits signed integer. + + +*function* ``wav_read_file_s32 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole wav audio file. Resulting sample format is 32 bits signed integer. + + +*function* ``wav_read_s16 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole wav audio data. Resulting sample format is 16 bits signed integer. + + +*function* ``wav_read_s32 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole wav audio data. Resulting sample format is 32 bits signed integer. + + +*function* ``wav_stream_file (filename: str, frames_to_read: int = 1024, seek_frame: int = 0) -> Generator[array.array, NoneType, NoneType]`` +> Streams the WAV audio file as interleaved 16 bit signed integer sample arrays segments. This uses +a fixed chunk size and cannot be used as a generic miniaudio decoder input stream. Consider using +stream_file() instead. + + +*function* ``wav_write_file (filename: str, sound: miniaudio.DecodedSoundFile) `` +> Writes the pcm sound to a WAV file + + +*function* ``width_from_format (sampleformat: miniaudio.SampleFormat) -> int`` +> returns the sample width in bytes, of the given sample format. + + +*class* ``CaptureDevice`` + +``CaptureDevice (self, input_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, buffersize_msec: int = 200, device_id: Optional[_cffi_backend._CDataBase] = None, callback_periods: int = 0, backends: Optional[List[miniaudio.Backend]] = None, thread_prio: miniaudio.ThreadPriority = <ThreadPriority.HIGHEST: 0>, app_name: str = '') `` +> An audio device provided by miniaudio, for audio capture (recording). + +> *method* ``close (self) `` +> > Halt playback or capture and close down the device. If you use the device as a context manager, +it will be closed automatically. + +> *method* ``start (self, callback_generator: Generator[NoneType, Union[bytes, array.array], NoneType]) `` +> > Start the audio device: capture (recording) begins. The recorded audio data is sent to the given +callback generator as raw bytes. (it should already be started before) + +> *method* ``stop (self) `` +> > Halt playback or capture. + + +*class* ``DecodeError`` + +``DecodeError (self, /, *args, **kwargs)`` +> When something went wrong during decoding an audio file. + + +*class* ``DecodedSoundFile`` + +``DecodedSoundFile (self, name: str, nchannels: int, sample_rate: int, sample_format: miniaudio.SampleFormat, samples: array.array) `` +> Contains various properties and also the PCM frames of a fully decoded audio file. + + +*class* ``Devices`` + +``Devices (self, backends: Optional[List[miniaudio.Backend]] = None) `` +> Query the audio playback and record devices that miniaudio provides + +> *method* ``get_captures (self) -> List[Dict[str, Any]]`` +> > Get a list of capture devices and some details about them + +> *method* ``get_playbacks (self) -> List[Dict[str, Any]]`` +> > Get a list of playback devices and some details about them + + +*class* ``DuplexStream`` + +``DuplexStream (self, playback_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, playback_channels: int = 2, capture_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, capture_channels: int = 2, sample_rate: int = 44100, buffersize_msec: int = 200, playback_device_id: Optional[_cffi_backend._CDataBase] = None, capture_device_id: Optional[_cffi_backend._CDataBase] = None, callback_periods: int = 0, backends: Optional[List[miniaudio.Backend]] = None, thread_prio: miniaudio.ThreadPriority = <ThreadPriority.HIGHEST: 0>, app_name: str = '') `` +> Joins a capture device and a playback device. + +> *method* ``close (self) `` +> > Halt playback or capture and close down the device. If you use the device as a context manager, +it will be closed automatically. + +> *method* ``start (self, callback_generator: Generator[Union[bytes, array.array], Union[bytes, array.array], NoneType]) `` +> > Start the audio device: playback and capture begin. The audio data for playback is provided by +the given callback generator, which is sent the recorded audio data at the same time. (it should +already be started before passing it in) + +> *method* ``stop (self) `` +> > Halt playback or capture. + + +*class* ``IceCastClient`` + +``IceCastClient (self, url: str, update_stream_title: Callable[[ForwardRef('IceCastClient'), str], NoneType] = None, ssl_context: 'ssl.SSLContext' = None) `` +> A simple client for IceCast audio streams as miniaudio streamable source. If the stream has Icy +MetaData, the stream_title attribute will be updated with the actual title taken from the metadata. +You can also provide a callback to be called when a new stream title is available. The downloading +of the data from the internet is done in a background thread and it tries to keep a (small) buffer +filled with available data to read. You can optionally provide a custom ssl.SSLContext in the +ssl_context parameter, if you need to change the way SSL connections are configured (certificates, +checks, etc). + +> *method* ``close (self) `` +> > Stop the stream, aborting the background downloading. + +> *method* ``read (self, num_bytes: int) -> bytes`` +> > Read a chunk of data from the stream. + +> *method* ``seek (self, offset: int, origin: miniaudio.SeekOrigin) -> bool`` +> > Override this if the stream supports seeking. Note: seek support is sometimes not needed if you +give the file type to a decoder upfront. You can ignore this method then. + + +*class* ``MiniaudioError`` + +``MiniaudioError (self, /, *args, **kwargs)`` +> When a miniaudio specific error occurs. + + +*class* ``PlaybackDevice`` + +``PlaybackDevice (self, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, buffersize_msec: int = 200, device_id: Optional[_cffi_backend._CDataBase] = None, callback_periods: int = 0, backends: Optional[List[miniaudio.Backend]] = None, thread_prio: miniaudio.ThreadPriority = <ThreadPriority.HIGHEST: 0>, app_name: str = '') `` +> An audio device provided by miniaudio, for audio playback. + +> *method* ``close (self) `` +> > Halt playback or capture and close down the device. If you use the device as a context manager, +it will be closed automatically. + +> *method* ``start (self, callback_generator: Generator[Union[bytes, array.array], int, NoneType]) `` +> > Start the audio device: playback begins. The audio data is provided by the given callback +generator. The generator gets sent the required number of frames and should yield the sample data as +raw bytes, a memoryview, an array.array, or as a numpy array with shape (numframes, numchannels). +The generator should already be started before passing it in. + +> *method* ``stop (self) `` +> > Halt playback or capture. + + +*class* ``SoundFileInfo`` + +``SoundFileInfo (self, name: str, file_format: miniaudio.FileFormat, nchannels: int, sample_rate: int, sample_format: miniaudio.SampleFormat, duration: float, num_frames: int, sub_format: int = None) `` +> Contains various properties of an audio file. + + +*class* ``StreamableSource`` + +``StreamableSource (self, /, *args, **kwargs)`` +> Base class for streams of audio data bytes. Can be used as a contextmanager, to properly call +close(). + +> *method* ``close (self) `` +> > Override this to properly close the stream and free resources. + +> *method* ``read (self, num_bytes: int) -> Union[bytes, memoryview]`` +> > override this to provide data bytes to the consumer of the stream + +> *method* ``seek (self, offset: int, origin: miniaudio.SeekOrigin) -> bool`` +> > Override this if the stream supports seeking. Note: seek support is sometimes not needed if you +give the file type to a decoder upfront. You can ignore this method then. + + +*class* ``WavFileReadStream`` + +``WavFileReadStream (self, pcm_sample_gen: Generator[Union[bytes, array.array], int, NoneType], sample_rate: int, nchannels: int, output_format: miniaudio.SampleFormat, max_frames: int = 0) `` +> An IO stream that reads as a .wav file, and which gets its pcm samples from the provided producer + +> *method* ``close (self) `` +> > Close the file + +> *method* ``read (self, amount: int = 9223372036854775807) -> Optional[bytes]`` +> > Read up to the given amount of bytes from the file. + + + + + + + +%package help +Summary: Development documents and examples for miniaudio +Provides: python3-miniaudio-doc +%description help +[](https://pypi.python.org/pypi/miniaudio/) + + +# Python miniaudio + +Multiplatform audio playback, recording, decoding and sample format conversion for +Linux (including Raspberri Pi), Windows, Mac and others. + +Installation for most users: via [Pypi](https://pypi.org/project/miniaudio/), Raspberri Pi builds via [PiWheels](https://www.piwheels.org/project/miniaudio/). + + +This is a Pythonic interface to the cross-platform [miniaudio](https://github.com/dr-soft/miniaudio/) C library: + +- audio operations run in the background +- python bindings for most of the functions offered in the miniaudio library: + - reading and decoding audio files + - getting audio file properties (such as duration, number of channels, sample rate) + - converting sample formats and frequencies + - streaming large audio files + - audio playback + - audio recording +- decoders for wav, flac, vorbis and mp3 +- Audio file and Icecast internet radio streaming +- Python enums instead of just some integers for special values +- several classes to represent the main functions of the library +- generators for the Audio playback and recording +- sample data is usually in the form of a Python ``array`` with appropriately sized elements + depending on the sample width (rather than a raw block of bytes) +- TODO: filters, waveform generators? + + +*Requires Python 3.6 or newer. Also works on pypy3 (because it uses cffi).* + +Software license for these Python bindings, miniaudio and the decoders: MIT + +## Synthesizer, modplayer? + +If you like this library you may also be interested in my [software FM synthesizer](https://pypi.org/project/synthplayer/) +or my [mod player](https://pypi.org/project/libxmplite/) which uses libxmp. + + +## Examples + +### Most basic audio file playback + +```python +import miniaudio +stream = miniaudio.stream_file("samples/music.mp3") +with miniaudio.PlaybackDevice() as device: + device.start(stream) + input("Audio file playing in the background. Enter to stop playback: ") +``` + +### Playback of an unsupported file format + +This example uses ffmpeg as an external tool to decode an audio file in a format +that miniaudio itself can't decode (m4a/aac in this case): + +```python +import subprocess +import miniaudio + +channels = 2 +sample_rate = 44100 +sample_width = 2 # 16 bit pcm +filename = "samples/music.m4a" # AAC encoded audio file + +def stream_pcm(source): + required_frames = yield b"" # generator initialization + while True: + required_bytes = required_frames * channels * sample_width + sample_data = source.read(required_bytes) + if not sample_data: + break + print(".", end="", flush=True) + required_frames = yield sample_data + +with miniaudio.PlaybackDevice(output_format=miniaudio.SampleFormat.SIGNED16, + nchannels=channels, sample_rate=sample_rate) as device: + ffmpeg = subprocess.Popen(["ffmpeg", "-v", "fatal", "-hide_banner", "-nostdin", + "-i", filename, "-f", "s16le", "-acodec", "pcm_s16le", + "-ac", str(channels), "-ar", str(sample_rate), "-"], + stdin=None, stdout=subprocess.PIPE) + stream = stream_pcm(ffmpeg.stdout) + next(stream) # start the generator + device.start(stream) + input("Audio file playing in the background. Enter to stop playback: ") + ffmpeg.terminate() +``` + +## API + +### Note: everything below is automatically generated from comments in the source code files. Do not edit in this readme directly. + +*enum class* ``Backend`` + names: ``WASAPI`` ``DSOUND`` ``WINMM`` ``COREAUDIO`` ``SNDIO`` ``AUDIO4`` ``OSS`` ``PULSEAUDIO`` ``ALSA`` ``JACK`` ``AAUDIO`` ``OPENSL`` ``WEBAUDIO`` ``CUSTOM`` ``NULL`` +> Operating system audio backend to use (only a subset will be available) + + +*enum class* ``ChannelMixMode`` + names: ``RECTANGULAR`` ``SIMPLE`` ``CUSTOMWEIGHTS`` +> How to mix channels when converting + + +*enum class* ``DeviceType`` + names: ``PLAYBACK`` ``CAPTURE`` ``DUPLEX`` +> Type of audio device + + +*enum class* ``DitherMode`` + names: ``NONE`` ``RECTANGLE`` ``TRIANGLE`` +> How to dither when converting + + +*enum class* ``FileFormat`` + names: ``UNKNOWN`` ``WAV`` ``FLAC`` ``MP3`` ``VORBIS`` +> Audio file format + + +*enum class* ``SampleFormat`` + names: ``UNKNOWN`` ``UNSIGNED8`` ``SIGNED16`` ``SIGNED24`` ``SIGNED32`` ``FLOAT32`` +> Sample format in memory + + +*enum class* ``SeekOrigin`` + names: ``START`` ``CURRENT`` +> How to seek() in a source + + +*enum class* ``ThreadPriority`` + names: ``IDLE`` ``LOWEST`` ``LOW`` ``NORMAL`` ``HIGH`` ``HIGHEST`` ``REALTIME`` +> The priority of the worker thread (default=HIGHEST) + + +*function* ``convert_frames (from_fmt: miniaudio.SampleFormat, from_numchannels: int, from_samplerate: int, sourcedata: bytes, to_fmt: miniaudio.SampleFormat, to_numchannels: int, to_samplerate: int) -> bytearray`` +> Convert audio frames in source sample format with a certain number of channels, to another sample +format and possibly down/upmixing the number of channels as well. + + +*function* ``convert_sample_format (from_fmt: miniaudio.SampleFormat, sourcedata: bytes, to_fmt: miniaudio.SampleFormat, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>) -> bytearray`` +> Convert a raw buffer of pcm samples to another sample format. The result is returned as another +raw pcm sample buffer + + +*function* ``decode (data: bytes, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>) -> miniaudio.DecodedSoundFile`` +> Convenience function to decode any supported audio file in memory to raw PCM samples in your +chosen format. + + +*function* ``decode_file (filename: str, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>) -> miniaudio.DecodedSoundFile`` +> Convenience function to decode any supported audio file to raw PCM samples in your chosen format. + + +*function* ``flac_get_file_info (filename: str) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio file (flac format). + + +*function* ``flac_get_info (data: bytes) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio data (flac format). + + +*function* ``flac_read_f32 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole flac audio file. Resulting sample format is 32 bits float. + + +*function* ``flac_read_file_f32 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole flac audio file. Resulting sample format is 32 bits float. + + +*function* ``flac_read_file_s16 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole flac audio file. Resulting sample format is 16 bits signed integer. + + +*function* ``flac_read_file_s32 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole flac audio file. Resulting sample format is 32 bits signed integer. + + +*function* ``flac_read_s16 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole flac audio data. Resulting sample format is 16 bits signed integer. + + +*function* ``flac_read_s32 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole flac audio data. Resulting sample format is 32 bits signed integer. + + +*function* ``flac_stream_file (filename: str, frames_to_read: int = 1024, seek_frame: int = 0) -> Generator[array.array, NoneType, NoneType]`` +> Streams the flac audio file as interleaved 16 bit signed integer sample arrays segments. This uses +a fixed chunk size and cannot be used as a generic miniaudio decoder input stream. Consider using +stream_file() instead. + + +*function* ``get_enabled_backends () -> Set[miniaudio.Backend]`` +> Returns the set of available backends by the compilation environment for the underlying miniaudio +C library + + +*function* ``get_file_info (filename: str) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio file. + + +*function* ``is_backend_enabled (backend: miniaudio.Backend) -> bool`` +> Determines whether or not the given backend is available by the compilation environment for the +underlying miniaudio C library + + +*function* ``is_loopback_supported (backend: miniaudio.Backend) -> bool`` +> Determines whether or not loopback mode is support by a backend. + + +*function* ``lib_version () -> str`` +> Returns the version string of the underlying miniaudio C library + + +*function* ``mp3_get_file_info (filename: str) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio file (mp3 format). + + +*function* ``mp3_get_info (data: bytes) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio data (mp3 format). + + +*function* ``mp3_read_f32 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole mp3 audio data. Resulting sample format is 32 bits float. + + +*function* ``mp3_read_file_f32 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole mp3 audio file. Resulting sample format is 32 bits float. + + +*function* ``mp3_read_file_s16 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole mp3 audio file. Resulting sample format is 16 bits signed integer. + + +*function* ``mp3_read_s16 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole mp3 audio data. Resulting sample format is 16 bits signed integer. + + +*function* ``mp3_stream_file (filename: str, frames_to_read: int = 1024, seek_frame: int = 0) -> Generator[array.array, NoneType, NoneType]`` +> Streams the mp3 audio file as interleaved 16 bit signed integer sample arrays segments. This uses +a fixed chunk size and cannot be used as a generic miniaudio decoder input stream. Consider using +stream_file() instead. + + +*function* ``read_file (filename: str, convert_to_16bit: bool = False) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole audio file. Miniaudio will attempt to return the sound data in exactly +the same format as in the file. Unless you set convert_convert_to_16bit to True, then the result is +always a 16 bit sample format. + + +*function* ``stream_any (source: miniaudio.StreamableSource, source_format: miniaudio.FileFormat = <FileFormat.UNKNOWN: 0>, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, frames_to_read: int = 1024, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>, seek_frame: int = 0) -> Generator[array.array, int, NoneType]`` +> Convenience function that returns a generator to decode and stream any source of encoded audio +data (such as a network stream). Stream result is chunks of raw PCM samples in the chosen format. If +you send() a number into the generator rather than just using next() on it, you'll get that given +number of frames, instead of the default configured amount. This is particularly useful to plug this +stream into an audio device callback that wants a variable number of frames per call. + + +*function* ``stream_file (filename: str, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, frames_to_read: int = 1024, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>, seek_frame: int = 0) -> Generator[array.array, int, NoneType]`` +> Convenience generator function to decode and stream any supported audio file as chunks of raw PCM +samples in the chosen format. If you send() a number into the generator rather than just using +next() on it, you'll get that given number of frames, instead of the default configured amount. This +is particularly useful to plug this stream into an audio device callback that wants a variable +number of frames per call. + + +*function* ``stream_memory (data: bytes, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, frames_to_read: int = 1024, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>) -> Generator[array.array, int, NoneType]`` +> Convenience generator function to decode and stream any supported audio file in memory as chunks +of raw PCM samples in the chosen format. If you send() a number into the generator rather than just +using next() on it, you'll get that given number of frames, instead of the default configured +amount. This is particularly useful to plug this stream into an audio device callback that wants a +variable number of frames per call. + + +*function* ``stream_raw_pcm_memory (pcmdata: Union[array.array, memoryview, bytes], nchannels: int, sample_width: int, frames_to_read: int = 4096) -> Generator[Union[bytes, array.array], int, NoneType]`` +> Convenience generator function to stream raw pcm audio data from memory. Usually you don't need to +use this as the library provides many other streaming options that work on much smaller, encoded, +audio data. However, in the odd case that you only have already decoded raw pcm data you can use +this generator as a stream source. The data can be provided in ``array`` type or ``bytes``, +``memoryview`` or even a numpy array. Be sure to also specify the correct number of channels that +the audio data has, and the sample with in bytes. + + +*function* ``stream_with_callbacks (sample_stream: Generator[Union[bytes, array.array], int, NoneType], progress_callback: Optional[Callable[[int], NoneType]] = None, frame_process_method: Optional[Callable[[Union[bytes, array.array]], Union[bytes, array.array]]] = None, end_callback: Optional[Callable] = None) -> Generator[Union[bytes, array.array], int, NoneType]`` +> Convenience generator function to add callback and processing functionality to another stream. You +can specify : > A callback function that gets called during play and takes an int for the number of +frames played. > A function that can be used to process raw data frames before they are yielded +back (takes an array.array or bytes, returns an array.array or bytes) *Note: if the processing +method is slow it will result in audio glitchiness > A callback function that gets called when the +stream ends playing. + + +*function* ``vorbis_get_file_info (filename: str) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio file (vorbis format). + + +*function* ``vorbis_get_info (data: bytes) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio data (vorbis format). + + +*function* ``vorbis_read (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole vorbis audio data. Resulting sample format is 16 bits signed integer. + + +*function* ``vorbis_read_file (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole vorbis audio file. Resulting sample format is 16 bits signed integer. + + +*function* ``vorbis_stream_file (filename: str, seek_frame: int = 0) -> Generator[array.array, NoneType, NoneType]`` +> Streams the ogg vorbis audio file as interleaved 16 bit signed integer sample arrays segments. +This uses a variable unconfigurable chunk size and cannot be used as a generic miniaudio decoder +input stream. Consider using stream_file() instead. + + +*function* ``wav_get_file_info (filename: str) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio file (wav format). + + +*function* ``wav_get_info (data: bytes) -> miniaudio.SoundFileInfo`` +> Fetch some information about the audio data (wav format). + + +*function* ``wav_read_f32 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole wav audio data. Resulting sample format is 32 bits float. + + +*function* ``wav_read_file_f32 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole wav audio file. Resulting sample format is 32 bits float. + + +*function* ``wav_read_file_s16 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole wav audio file. Resulting sample format is 16 bits signed integer. + + +*function* ``wav_read_file_s32 (filename: str) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole wav audio file. Resulting sample format is 32 bits signed integer. + + +*function* ``wav_read_s16 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole wav audio data. Resulting sample format is 16 bits signed integer. + + +*function* ``wav_read_s32 (data: bytes) -> miniaudio.DecodedSoundFile`` +> Reads and decodes the whole wav audio data. Resulting sample format is 32 bits signed integer. + + +*function* ``wav_stream_file (filename: str, frames_to_read: int = 1024, seek_frame: int = 0) -> Generator[array.array, NoneType, NoneType]`` +> Streams the WAV audio file as interleaved 16 bit signed integer sample arrays segments. This uses +a fixed chunk size and cannot be used as a generic miniaudio decoder input stream. Consider using +stream_file() instead. + + +*function* ``wav_write_file (filename: str, sound: miniaudio.DecodedSoundFile) `` +> Writes the pcm sound to a WAV file + + +*function* ``width_from_format (sampleformat: miniaudio.SampleFormat) -> int`` +> returns the sample width in bytes, of the given sample format. + + +*class* ``CaptureDevice`` + +``CaptureDevice (self, input_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, buffersize_msec: int = 200, device_id: Optional[_cffi_backend._CDataBase] = None, callback_periods: int = 0, backends: Optional[List[miniaudio.Backend]] = None, thread_prio: miniaudio.ThreadPriority = <ThreadPriority.HIGHEST: 0>, app_name: str = '') `` +> An audio device provided by miniaudio, for audio capture (recording). + +> *method* ``close (self) `` +> > Halt playback or capture and close down the device. If you use the device as a context manager, +it will be closed automatically. + +> *method* ``start (self, callback_generator: Generator[NoneType, Union[bytes, array.array], NoneType]) `` +> > Start the audio device: capture (recording) begins. The recorded audio data is sent to the given +callback generator as raw bytes. (it should already be started before) + +> *method* ``stop (self) `` +> > Halt playback or capture. + + +*class* ``DecodeError`` + +``DecodeError (self, /, *args, **kwargs)`` +> When something went wrong during decoding an audio file. + + +*class* ``DecodedSoundFile`` + +``DecodedSoundFile (self, name: str, nchannels: int, sample_rate: int, sample_format: miniaudio.SampleFormat, samples: array.array) `` +> Contains various properties and also the PCM frames of a fully decoded audio file. + + +*class* ``Devices`` + +``Devices (self, backends: Optional[List[miniaudio.Backend]] = None) `` +> Query the audio playback and record devices that miniaudio provides + +> *method* ``get_captures (self) -> List[Dict[str, Any]]`` +> > Get a list of capture devices and some details about them + +> *method* ``get_playbacks (self) -> List[Dict[str, Any]]`` +> > Get a list of playback devices and some details about them + + +*class* ``DuplexStream`` + +``DuplexStream (self, playback_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, playback_channels: int = 2, capture_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, capture_channels: int = 2, sample_rate: int = 44100, buffersize_msec: int = 200, playback_device_id: Optional[_cffi_backend._CDataBase] = None, capture_device_id: Optional[_cffi_backend._CDataBase] = None, callback_periods: int = 0, backends: Optional[List[miniaudio.Backend]] = None, thread_prio: miniaudio.ThreadPriority = <ThreadPriority.HIGHEST: 0>, app_name: str = '') `` +> Joins a capture device and a playback device. + +> *method* ``close (self) `` +> > Halt playback or capture and close down the device. If you use the device as a context manager, +it will be closed automatically. + +> *method* ``start (self, callback_generator: Generator[Union[bytes, array.array], Union[bytes, array.array], NoneType]) `` +> > Start the audio device: playback and capture begin. The audio data for playback is provided by +the given callback generator, which is sent the recorded audio data at the same time. (it should +already be started before passing it in) + +> *method* ``stop (self) `` +> > Halt playback or capture. + + +*class* ``IceCastClient`` + +``IceCastClient (self, url: str, update_stream_title: Callable[[ForwardRef('IceCastClient'), str], NoneType] = None, ssl_context: 'ssl.SSLContext' = None) `` +> A simple client for IceCast audio streams as miniaudio streamable source. If the stream has Icy +MetaData, the stream_title attribute will be updated with the actual title taken from the metadata. +You can also provide a callback to be called when a new stream title is available. The downloading +of the data from the internet is done in a background thread and it tries to keep a (small) buffer +filled with available data to read. You can optionally provide a custom ssl.SSLContext in the +ssl_context parameter, if you need to change the way SSL connections are configured (certificates, +checks, etc). + +> *method* ``close (self) `` +> > Stop the stream, aborting the background downloading. + +> *method* ``read (self, num_bytes: int) -> bytes`` +> > Read a chunk of data from the stream. + +> *method* ``seek (self, offset: int, origin: miniaudio.SeekOrigin) -> bool`` +> > Override this if the stream supports seeking. Note: seek support is sometimes not needed if you +give the file type to a decoder upfront. You can ignore this method then. + + +*class* ``MiniaudioError`` + +``MiniaudioError (self, /, *args, **kwargs)`` +> When a miniaudio specific error occurs. + + +*class* ``PlaybackDevice`` + +``PlaybackDevice (self, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, buffersize_msec: int = 200, device_id: Optional[_cffi_backend._CDataBase] = None, callback_periods: int = 0, backends: Optional[List[miniaudio.Backend]] = None, thread_prio: miniaudio.ThreadPriority = <ThreadPriority.HIGHEST: 0>, app_name: str = '') `` +> An audio device provided by miniaudio, for audio playback. + +> *method* ``close (self) `` +> > Halt playback or capture and close down the device. If you use the device as a context manager, +it will be closed automatically. + +> *method* ``start (self, callback_generator: Generator[Union[bytes, array.array], int, NoneType]) `` +> > Start the audio device: playback begins. The audio data is provided by the given callback +generator. The generator gets sent the required number of frames and should yield the sample data as +raw bytes, a memoryview, an array.array, or as a numpy array with shape (numframes, numchannels). +The generator should already be started before passing it in. + +> *method* ``stop (self) `` +> > Halt playback or capture. + + +*class* ``SoundFileInfo`` + +``SoundFileInfo (self, name: str, file_format: miniaudio.FileFormat, nchannels: int, sample_rate: int, sample_format: miniaudio.SampleFormat, duration: float, num_frames: int, sub_format: int = None) `` +> Contains various properties of an audio file. + + +*class* ``StreamableSource`` + +``StreamableSource (self, /, *args, **kwargs)`` +> Base class for streams of audio data bytes. Can be used as a contextmanager, to properly call +close(). + +> *method* ``close (self) `` +> > Override this to properly close the stream and free resources. + +> *method* ``read (self, num_bytes: int) -> Union[bytes, memoryview]`` +> > override this to provide data bytes to the consumer of the stream + +> *method* ``seek (self, offset: int, origin: miniaudio.SeekOrigin) -> bool`` +> > Override this if the stream supports seeking. Note: seek support is sometimes not needed if you +give the file type to a decoder upfront. You can ignore this method then. + + +*class* ``WavFileReadStream`` + +``WavFileReadStream (self, pcm_sample_gen: Generator[Union[bytes, array.array], int, NoneType], sample_rate: int, nchannels: int, output_format: miniaudio.SampleFormat, max_frames: int = 0) `` +> An IO stream that reads as a .wav file, and which gets its pcm samples from the provided producer + +> *method* ``close (self) `` +> > Close the file + +> *method* ``read (self, amount: int = 9223372036854775807) -> Optional[bytes]`` +> > Read up to the given amount of bytes from the file. + + + + + + + +%prep +%autosetup -n miniaudio-1.56 + +%build +%py3_build + +%install +%py3_install +install -d -m755 %{buildroot}/%{_pkgdocdir} +if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi +if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi +if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi +if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi +pushd %{buildroot} +if [ -d usr/lib ]; then + find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/lib64 ]; then + find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/bin ]; then + find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/sbin ]; then + find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst +fi +touch doclist.lst +if [ -d usr/share/man ]; then + find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst +fi +popd +mv %{buildroot}/filelist.lst . +mv %{buildroot}/doclist.lst . + +%files -n python3-miniaudio -f filelist.lst +%dir %{python3_sitearch}/* + +%files help -f doclist.lst +%{_docdir}/* + +%changelog +* Tue Apr 11 2023 Python_Bot <Python_Bot@openeuler.org> - 1.56-1 +- Package Spec generated @@ -0,0 +1 @@ +eaf024f2affa1f1df571d29bebefd8bb miniaudio-1.56.tar.gz |
