Mercurial > hg > auditok
changeset 418:70abdb92149a
Add AudioEventsJoinerWorker
author | Amine Sehili <amine.sehili@gmail.com> |
---|---|
date | Fri, 18 Oct 2024 22:47:58 +0200 |
parents | 5f32574c9788 |
children | c2ac3fc1bfbc |
files | auditok/cmdline.py auditok/cmdline_util.py auditok/workers.py pyproject.toml tests/test_cmdline_util.py tests/test_workers.py |
diffstat | 6 files changed, 345 insertions(+), 154 deletions(-) [+] |
line wrap: on
line diff
--- a/auditok/cmdline.py Thu Oct 17 22:02:41 2024 +0200 +++ b/auditok/cmdline.py Fri Oct 18 22:47:58 2024 +0200 @@ -22,11 +22,8 @@ from auditok import AudioRegion, __version__ -from . import workers from .cmdline_util import initialize_workers, make_kwargs, make_logger from .exceptions import AudioEncodingWarning, EndOfProcessing -from .io import player_for -from .util import AudioDataSource __all__ = [] __date__ = "2015-11-23" @@ -129,6 +126,17 @@ metavar="STRING", ) group.add_argument( + "-j", + "--join-detections", + dest="join_detections", + type=float, + default=None, + help="Join (i.e., glue) detected audio events with a silence of " + "this duration. Should be used jointly with the --save-stream / " + "-O option.", + metavar="FLOAT", + ) + group.add_argument( "-T", "--output-format", dest="output_format", @@ -380,11 +388,8 @@ args = parser.parse_args(argv) logger = make_logger(args.debug, args.debug_file) kwargs = make_kwargs(args) - reader, observers = initialize_workers( - logger=logger, **kwargs.io, **kwargs.miscellaneous - ) - tokenizer_worker = workers.TokenizerWorker( - reader, observers, logger=logger, **kwargs.split + stream_saver, tokenizer_worker = initialize_workers( + logger=logger, **kwargs.split, **kwargs.io, **kwargs.miscellaneous ) tokenizer_worker.start_all() @@ -397,16 +402,18 @@ if tokenizer_worker is not None: tokenizer_worker.stop_all() - if isinstance(reader, workers.StreamSaverWorker): - reader.join() + if stream_saver is not None: + stream_saver.join() try: - reader.save_stream() - except AudioEncodingWarning as ae_warn: - print(str(ae_warn), file=sys.stderr) + stream_saver.export_audio() + except Exception as aee: + print(aee, file=sys.stderr) if args.plot or args.save_image is not None: from .plotting import plot + reader = tokenizer_worker.reader + reader.rewind() record = AudioRegion( reader.data, reader.sr, reader.sw, reader.ch
--- a/auditok/cmdline_util.py Thu Oct 17 22:02:41 2024 +0200 +++ b/auditok/cmdline_util.py Fri Oct 18 22:47:58 2024 +0200 @@ -33,6 +33,7 @@ "use_channel": use_channel, "save_stream": args_ns.save_stream, "save_detections_as": args_ns.save_detections_as, + "join_detections": args_ns.join_detections, "export_format": args_ns.output_format, "large_file": args_ns.large_file, "frames_per_buffer": args_ns.frame_per_buffer, @@ -84,12 +85,30 @@ observers = [] reader = AudioReader(source=kwargs["input"], **kwargs) if kwargs["save_stream"] is not None: - reader = workers.StreamSaverWorker( - reader, - filename=kwargs["save_stream"], - export_format=kwargs["export_format"], - ) - reader.start() + + if kwargs["join_detections"] is not None: + print("Using event joiner...") + stream_saver = workers.AudioEventsJoinerWorker( + silence_duration=kwargs["join_detections"], + filename=kwargs["save_stream"], + export_format=kwargs["export_format"], + sampling_rate=reader.sampling_rate, + sample_width=reader.sample_width, + channels=reader.channels, + ) + observers.append(stream_saver) + + else: + print("Using full stream saver...") + reader = workers.StreamSaverWorker( + reader, + filename=kwargs["save_stream"], + export_format=kwargs["export_format"], + ) + stream_saver = reader + stream_saver.start() + else: + stream_saver = None if kwargs["save_detections_as"] is not None: worker = workers.RegionSaverWorker( @@ -124,4 +143,8 @@ ) observers.append(worker) - return reader, observers + tokenizer_worker = workers.TokenizerWorker( + reader, observers, logger=logger, **kwargs + ) + + return stream_saver, tokenizer_worker
--- a/auditok/workers.py Thu Oct 17 22:02:41 2024 +0200 +++ b/auditok/workers.py Fri Oct 18 22:47:58 2024 +0200 @@ -9,12 +9,8 @@ from tempfile import NamedTemporaryFile from threading import Thread -from .core import split -from .exceptions import ( - AudioEncodingError, - AudioEncodingWarning, - EndOfProcessing, -) +from .core import make_silence, split +from .exceptions import AudioEncodingError, AudioEncodingWarning from .io import _guess_audio_format from .util import AudioReader, make_duration_formatter @@ -90,7 +86,8 @@ def __init__(self, reader, observers=None, logger=None, **kwargs): self._observers = observers if observers is not None else [] self._reader = reader - self._audio_region_gen = split(self, **kwargs) + kwargs["input"] = self + self._audio_region_gen = split(**kwargs) self._detections = [] self._log_format = "[DET]: Detection {0.id} (start: {0.start:.3f}, " self._log_format += "end: {0.end:.3f}, duration: {0.duration:.3f})" @@ -103,6 +100,10 @@ def detections(self): return self._detections + @property + def reader(self): + return self._reader + def _notify_observers(self, message): for observer in self._observers: observer.send(message) @@ -150,27 +151,41 @@ return getattr(self._reader, name) -class StreamSaverWorker(Worker): +class AudioDataSaverWorker(Worker): + def __init__( self, - audio_reader, filename, - export_format=None, - cache_size_sec=0.5, + export_format, + sampling_rate, + sample_width, + channels, timeout=0.2, ): - self._reader = audio_reader - sample_size_bytes = self._reader.sw * self._reader.ch - self._cache_size = cache_size_sec * self._reader.sr * sample_size_bytes + + super().__init__(timeout=timeout) self._output_filename = filename + self._sampling_rate = sampling_rate + self._sample_width = sample_width + self._channels = channels + self._export_format = _guess_audio_format(filename, export_format) if self._export_format is None: self._export_format = "wav" self._init_output_stream() self._exported = False - self._cache = [] - self._total_cached = 0 - Worker.__init__(self, timeout=timeout) + + @property + def sr(self): + return self._sampling_rate + + @property + def sw(self): + return self._sample_width + + @property + def ch(self): + return self._channels def _get_non_existent_filename(self): filename = self._output_filename + ".wav" @@ -186,21 +201,90 @@ else: self._tmp_output_filename = self._output_filename self._wfp = wave.open(self._tmp_output_filename, "wb") - self._wfp.setframerate(self._reader.sr) - self._wfp.setsampwidth(self._reader.sw) - self._wfp.setnchannels(self._reader.ch) + self._wfp.setframerate(self.sr) + self._wfp.setsampwidth(self.sw) + self._wfp.setnchannels(self.ch) @property - def sr(self): - return self._reader.sampling_rate + def data(self): + with wave.open(self._tmp_output_filename, "rb") as wfp: + return wfp.readframes(-1) - @property - def sw(self): - return self._reader.sample_width + def export_audio(self): + try: + self._encode_export_audio() + except AudioEncodingError as ae_error: + raise AudioEncodingWarning(str(ae_error)) from ae_error + return self._output_filename - @property - def ch(self): - return self._reader.channels + def _encode_export_audio(self): + if self._exported: + return self._output_filename + + if self._export_format in ("raw", "wav"): + if self._export_format == "raw": + self._export_raw() + self._exported = True + return self._output_filename + try: + self._export_with_ffmpeg_or_avconv() + + except AudioEncodingError: + try: + self._export_with_sox() + except AudioEncodingError as exc: + warn_msg = "Couldn't save audio data in the desired format " + warn_msg += "'{}'.\nEither none of 'ffmpeg', 'avconv' or 'sox' " + warn_msg += "is installed or this format is not recognized.\n" + warn_msg += "Audio file was saved as '{}'" + raise AudioEncodingError( + warn_msg.format( + self._export_format, self._tmp_output_filename + ) + ) from exc + else: + self._exported = True + else: + self._exported = True + return self._output_filename + + def _export_raw(self): + with open(self._output_filename, "wb") as fp: + fp.write(self.data) + + def _export_with_ffmpeg_or_avconv(self): + command = [ + "-y", + "-f", + "wav", + "-i", + self._tmp_output_filename, + "-f", + self._export_format, + self._output_filename, + ] + returncode, stdout, stderr = _run_subprocess(["ffmpeg"] + command) + if returncode != 0: + returncode, stdout, stderr = _run_subprocess(["avconv"] + command) + if returncode != 0: + raise AudioEncodingError(stderr) + return stdout, stderr + + def _export_with_sox(self): + command = [ + "sox", + "-t", + "wav", + self._tmp_output_filename, + self._output_filename, + ] + returncode, stdout, stderr = _run_subprocess(command) + if returncode != 0: + raise AudioEncodingError(stderr) + return stdout, stderr + + def close_output(self): + self._wfp.close() def __del__(self): self._post_process() @@ -212,6 +296,33 @@ ): os.remove(self._tmp_output_filename) + +class StreamSaverWorker(AudioDataSaverWorker): + def __init__( + self, + audio_reader, + filename, + export_format=None, + cache_size_sec=0.5, + timeout=0.2, + ): + self._reader = audio_reader + super().__init__( + filename, + export_format, + self._reader.sr, + self._reader.sw, + self._reader.ch, + timeout=timeout, + ) + + sample_size_bytes = self._reader.sw * self._reader.ch + self._cache_size = cache_size_sec * self._reader.sr * sample_size_bytes + + self._exported = False + self._cache = [] + self._total_cached = 0 + def _process_message(self, data): self._cache.append(data) self._total_cached += len(data) @@ -253,72 +364,6 @@ with wave.open(self._tmp_output_filename, "rb") as wfp: return wfp.readframes(-1) - def save_stream(self): - if self._exported: - return self._output_filename - - if self._export_format in ("raw", "wav"): - if self._export_format == "raw": - self._export_raw() - self._exported = True - return self._output_filename - try: - self._export_with_ffmpeg_or_avconv() - except AudioEncodingError: - try: - self._export_with_sox() - except AudioEncodingError as exc: - warn_msg = "Couldn't save audio data in the desired format " - warn_msg += "'{}'. Either none of 'ffmpeg', 'avconv' or 'sox' " - warn_msg += "is installed or this format is not recognized.\n" - warn_msg += "Audio file was saved as '{}'" - raise AudioEncodingWarning( - warn_msg.format( - self._export_format, self._tmp_output_filename - ) - ) from exc - finally: - self._exported = True - return self._output_filename - - def _export_raw(self): - with open(self._output_filename, "wb") as wfp: - wfp.write(self.data) - - def _export_with_ffmpeg_or_avconv(self): - command = [ - "-y", - "-f", - "wav", - "-i", - self._tmp_output_filename, - "-f", - self._export_format, - self._output_filename, - ] - returncode, stdout, stderr = _run_subprocess(["ffmpeg"] + command) - if returncode != 0: - returncode, stdout, stderr = _run_subprocess(["avconv"] + command) - if returncode != 0: - raise AudioEncodingError(stderr) - return stdout, stderr - - def _export_with_sox(self): - command = [ - "sox", - "-t", - "wav", - self._tmp_output_filename, - self._output_filename, - ] - returncode, stdout, stderr = _run_subprocess(command) - if returncode != 0: - raise AudioEncodingError(stderr) - return stdout, stderr - - def close_output(self): - self._wfp.close() - def read(self): data = self._reader.read() if data is not None: @@ -328,9 +373,60 @@ return data def __getattr__(self, name): - if name == "data": - return self.data - return getattr(self._reader, name) + try: + return getattr(self._reader, name) + except AttributeError: + return getattr(self, name) + + +class AudioEventsJoinerWorker(AudioDataSaverWorker): + + def __init__( + self, + silence_duration, + filename, + export_format, + sampling_rate, + sample_width, + channels, + timeout=0.2, + ): + + super().__init__( + filename, + export_format, + sampling_rate, + sample_width, + channels, + timeout, + ) + + self._silence_data = make_silence( + silence_duration, sampling_rate, sample_width, channels + ).data + self._first_event = True + + def _process_message(self, message): + _, audio_event = message + self._write_audio_event(audio_event.data) + + def _post_process(self): + while True: + try: + message = self._inbox.get_nowait() + if message != _STOP_PROCESSING: + _, audio_event = message + self._write_audio_event(audio_event.data) + except Empty: + break + self._wfp.close() + + def _write_audio_event(self, data): + if not self._first_event: + self._wfp.writeframes(self._silence_data) + else: + self._first_event = False + self._wfp.writeframes(data) class PlayerWorker(Worker): @@ -357,7 +453,7 @@ audio_format=None, timeout=0.2, logger=None, - **audio_parameters + **audio_parameters, ): self._filename_format = filename_format self._audio_format = audio_format
--- a/pyproject.toml Thu Oct 17 22:02:41 2024 +0200 +++ b/pyproject.toml Fri Oct 18 22:47:58 2024 +0200 @@ -14,3 +14,6 @@ | dist )/ ''' + +[tool.isort] +profile = "black"
--- a/tests/test_cmdline_util.py Thu Oct 17 22:02:41 2024 +0200 +++ b/tests/test_cmdline_util.py Fri Oct 18 22:47:58 2024 +0200 @@ -13,6 +13,7 @@ make_logger, ) from auditok.workers import ( + AudioEventsJoinerWorker, CommandLineWorker, PlayerWorker, PrintWorker, @@ -37,6 +38,7 @@ "input_device_index", "save_stream", "save_detections_as", + "join_detections", "plot", "save_image", "min_duration", @@ -57,25 +59,25 @@ @pytest.mark.parametrize( - "save_stream, save_detections_as, plot, save_image, use_channel, exp_use_channel, exp_record", + "save_stream, save_detections_as, join_detections, plot, save_image, use_channel, exp_use_channel, exp_record", # noqa: B950 [ - # no_record - ("stream.ogg", None, False, None, "mix", "mix", False), - # no_record_plot - ("stream.ogg", None, True, None, None, None, False), + # no_record_no_join + ("stream.ogg", None, None, False, None, "mix", "mix", False), + # no_record_plot_join + ("stream.ogg", None, 1.0, True, None, None, None, False), # no_record_save_image - ("stream.ogg", None, True, "image.png", None, None, False), + ("stream.ogg", None, None, True, "image.png", None, None, False), # record_plot - (None, None, True, None, None, None, True), + (None, None, None, True, None, None, None, True), # record_save_image - (None, None, False, "image.png", None, None, True), + (None, None, None, False, "image.png", None, None, True), # int_use_channel - ("stream.ogg", None, False, None, "1", 1, False), + ("stream.ogg", None, None, False, None, "1", 1, False), # save_detections_as - ("stream.ogg", "{id}.wav", False, None, None, None, False), + ("stream.ogg", "{id}.wav", None, False, None, None, None, False), ], ids=[ - "no_record", + "no_record_no_join", "no_record_plot", "no_record_save_image", "record_plot", @@ -87,6 +89,7 @@ def test_make_kwargs( save_stream, save_detections_as, + join_detections, plot, save_image, use_channel, @@ -108,6 +111,7 @@ 1, save_stream, save_detections_as, + join_detections, plot, save_image, 0.2, @@ -138,6 +142,7 @@ "use_channel": exp_use_channel, "save_stream": save_stream, "save_detections_as": save_detections_as, + "join_detections": join_detections, "audio_format": "raw", "export_format": "ogg", "large_file": True, @@ -187,15 +192,16 @@ assert logger is None -def test_initialize_workers_all(): +def test_initialize_workers_all_plus_full_stream_saver(): with patch("auditok.cmdline_util.player_for") as patched_player_for: with TemporaryDirectory() as tmpdir: export_filename = os.path.join(tmpdir, "output.wav") - reader, observers = initialize_workers( + reader, tokenizer_worker = initialize_workers( input="tests/data/test_16KHZ_mono_400Hz.wav", save_stream=export_filename, export_format="wave", save_detections_as="{id}.wav", + join_detections=None, echo=True, progress_bar=False, command="some command", @@ -208,13 +214,48 @@ assert patched_player_for.called assert isinstance(reader, StreamSaverWorker) for obs, cls in zip( - observers, + tokenizer_worker._observers, [ RegionSaverWorker, PlayerWorker, CommandLineWorker, PrintWorker, ], + strict=True, + ): + assert isinstance(obs, cls) + + +def test_initialize_workers_all_plus_audio_event_joiner(): + with patch("auditok.cmdline_util.player_for") as patched_player_for: + with TemporaryDirectory() as tmpdir: + export_filename = os.path.join(tmpdir, "output.wav") + reader, tokenizer_worker = initialize_workers( + input="tests/data/test_16KHZ_mono_400Hz.wav", + save_stream=export_filename, + export_format="wave", + save_detections_as="{id}.wav", + join_detections=1, + echo=True, + progress_bar=False, + command="some command", + quiet=False, + printf="abcd", + time_format="%S", + timestamp_format="%h:%M:%S", + ) + assert patched_player_for.called + assert not isinstance(reader, StreamSaverWorker) + for obs, cls in zip( + tokenizer_worker._observers, + [ + AudioEventsJoinerWorker, + RegionSaverWorker, + PlayerWorker, + CommandLineWorker, + PrintWorker, + ], + strict=True, ): assert isinstance(obs, cls) @@ -223,11 +264,12 @@ with patch("auditok.cmdline_util.player_for") as patched_player_for: with TemporaryDirectory() as tmpdir: export_filename = os.path.join(tmpdir, "output.wav") - reader, observers = initialize_workers( + reader, tokenizer_worker = initialize_workers( input="tests/data/test_16KHZ_mono_400Hz.wav", save_stream=export_filename, export_format="wave", save_detections_as=None, + join_detections=None, echo=True, progress_bar=False, command="some command", @@ -240,7 +282,9 @@ assert patched_player_for.called assert isinstance(reader, StreamSaverWorker) for obs, cls in zip( - observers, [PlayerWorker, CommandLineWorker, PrintWorker] + tokenizer_worker._observers, + [PlayerWorker, CommandLineWorker, PrintWorker], + strict=True, ): assert isinstance(obs, cls) @@ -249,11 +293,12 @@ with patch("auditok.cmdline_util.player_for") as patched_player_for: with TemporaryDirectory() as tmpdir: export_filename = os.path.join(tmpdir, "output.wav") - reader, observers = initialize_workers( + reader, tokenizer_worker = initialize_workers( input="tests/data/test_16KHZ_mono_400Hz.wav", save_stream=export_filename, export_format="wave", save_detections_as="{id}.wav", + join_detections=None, echo=False, progress_bar=False, command="some command", @@ -266,8 +311,9 @@ assert not patched_player_for.called assert isinstance(reader, StreamSaverWorker) for obs, cls in zip( - observers, + tokenizer_worker._observers, [RegionSaverWorker, CommandLineWorker, PrintWorker], + strict=True, ): assert isinstance(obs, cls) @@ -276,11 +322,12 @@ with patch("auditok.cmdline_util.player_for") as patched_player_for: with TemporaryDirectory() as tmpdir: export_filename = os.path.join(tmpdir, "output.wav") - reader, observers = initialize_workers( + reader, tokenizer_worker = initialize_workers( input="tests/data/test_16KHZ_mono_400Hz.wav", save_stream=export_filename, export_format="wave", save_detections_as="{id}.wav", + join_detections=None, echo=True, progress_bar=False, command=None, @@ -293,7 +340,9 @@ assert patched_player_for.called assert isinstance(reader, StreamSaverWorker) for obs, cls in zip( - observers, [RegionSaverWorker, PlayerWorker, PrintWorker] + tokenizer_worker._observers, + [RegionSaverWorker, PlayerWorker, PrintWorker], + strict=True, ): assert isinstance(obs, cls) @@ -302,11 +351,12 @@ with patch("auditok.cmdline_util.player_for") as patched_player_for: with TemporaryDirectory() as tmpdir: export_filename = os.path.join(tmpdir, "output.wav") - reader, observers = initialize_workers( + reader, tokenizer_worker = initialize_workers( input="tests/data/test_16KHZ_mono_400Hz.wav", save_stream=export_filename, export_format="wave", save_detections_as="{id}.wav", + join_detections=None, echo=True, progress_bar=False, command="some command", @@ -319,15 +369,16 @@ assert patched_player_for.called assert isinstance(reader, StreamSaverWorker) for obs, cls in zip( - observers, + tokenizer_worker._observers, [RegionSaverWorker, PlayerWorker, CommandLineWorker], + strict=True, ): assert isinstance(obs, cls) def test_initialize_workers_no_observers(): with patch("auditok.cmdline_util.player_for") as patched_player_for: - reader, observers = initialize_workers( + reader, tokenizer_worker = initialize_workers( input="tests/data/test_16KHZ_mono_400Hz.wav", save_stream=None, export_format="wave", @@ -342,4 +393,4 @@ ) assert patched_player_for.called assert not isinstance(reader, StreamSaverWorker) - assert len(observers) == 1 + assert len(tokenizer_worker._observers) == 1
--- a/tests/test_workers.py Thu Oct 17 22:02:41 2024 +0200 +++ b/tests/test_workers.py Fri Oct 18 22:47:58 2024 +0200 @@ -4,6 +4,7 @@ import pytest +import auditok.workers from auditok import AudioReader, AudioRegion from auditok.cmdline_util import make_logger from auditok.exceptions import AudioEncodingWarning @@ -65,7 +66,8 @@ ) assert len(tokenizer.detections) == len(expected_detections) for i, (det, exp, log_line) in enumerate( - zip(tokenizer.detections, expected_detections, log_lines), 1 + zip(tokenizer.detections, expected_detections, log_lines, strict=True), + 1, ): start, end = exp exp_log_line = log_fmt.format(i, start, end, end - start) @@ -103,7 +105,8 @@ assert len(tokenizer.detections) == len(expected_detections) log_fmt = "[PLAY]: Detection {id} played" for i, (det, exp, log_line) in enumerate( - zip(tokenizer.detections, expected_detections, log_lines), 1 + zip(tokenizer.detections, expected_detections, log_lines, strict=False), + 1, ): start, end = exp exp_log_line = log_fmt.format(id=i) @@ -156,7 +159,8 @@ log_fmt = "[SAVE]: Detection {id} saved as '{filename}'" for i, (det, exp, log_line) in enumerate( - zip(tokenizer.detections, expected_detections, log_lines), 1 + zip(tokenizer.detections, expected_detections, log_lines, strict=False), + 1, ): start, end = exp expected_filename = filename_format.format( @@ -199,7 +203,8 @@ assert len(tokenizer.detections) == len(expected_detections) log_fmt = "[COMMAND]: Detection {id} command '{command}'" for i, (det, exp, log_line) in enumerate( - zip(tokenizer.detections, expected_detections, log_lines), 1 + zip(tokenizer.detections, expected_detections, log_lines, strict=False), + 1, ): start, end = exp exp_log_line = log_fmt.format(id=i, command=command_format) @@ -237,7 +242,7 @@ ] assert patched_print.mock_calls == expected_print_calls assert len(tokenizer.detections) == len(expected_detections) - for det, exp in zip(tokenizer.detections, expected_detections): + for det, exp in zip(tokenizer.detections, expected_detections, strict=True): start, end = exp assert pytest.approx(det.start) == start assert pytest.approx(det.end) == end @@ -254,7 +259,7 @@ tokenizer.join() saver.join() - output_filename = saver.save_stream() + output_filename = saver.export_audio() region = AudioRegion.load( "tests/data/test_split_10HZ_mono.raw", sr=10, sw=2, ch=1 ) @@ -276,7 +281,7 @@ tokenizer.start_all() tokenizer.join() saver.join() - output_filename = saver.save_stream() + output_filename = saver.export_audio() region = AudioRegion.load( "tests/data/test_split_10HZ_mono.raw", sr=10, sw=2, ch=1 ) @@ -295,18 +300,24 @@ expected_filename = os.path.join(tmpdir, "output.ogg") tmp_expected_filename = expected_filename + ".wav" saver = StreamSaverWorker(audio_data_source, expected_filename) + print("########## saver._exported 1:", saver._exported) + # import auditok + + # with pytest.raises(auditok.workers.AudioEncodingWarning) as rt_warn: saver.start() tokenizer = TokenizerWorker(saver) tokenizer.start_all() tokenizer.join() saver.join() - with pytest.raises(AudioEncodingWarning) as rt_warn: - saver.save_stream() + + with pytest.raises(auditok.workers.AudioEncodingError) as ae_error: + saver._encode_export_audio() + warn_msg = "Couldn't save audio data in the desired format " - warn_msg += "'ogg'. Either none of 'ffmpeg', 'avconv' or 'sox' " + warn_msg += "'ogg'.\nEither none of 'ffmpeg', 'avconv' or 'sox' " warn_msg += "is installed or this format is not recognized.\n" warn_msg += "Audio file was saved as '{}'" - assert warn_msg.format(tmp_expected_filename) == str(rt_warn.value) + assert warn_msg.format(tmp_expected_filename) == str(ae_error.value) ffmpef_avconv = [ "-y", "-f", @@ -334,5 +345,5 @@ region = AudioRegion.load( "tests/data/test_split_10HZ_mono.raw", sr=10, sw=2, ch=1 ) - assert saver._exported + assert not saver._exported assert saver.data == bytes(region)