Skip to content

Commit

Permalink
Engine (#50)
Browse files Browse the repository at this point in the history
* feat : Engine enum added

* feat : engine added to play function

* fix : __play_win function renamed to __play_winsound

* fix : __play_mac function renamed to __play_afplay

* fix : __play_linux function renamed to __play_alsa

* doc : docstrings updated

* doc : docstrings updated

* doc : ENGINE_TYPE_ERROR added

* fix : tests updated

* fix : minor bug in tests fixed

* fix : minor bug in function_test.py fixed

* fix : error_test.py updated

* doc : README.md updated

* doc : README.md updated

* doc : CHANGELOG.md updated

* doc : engine example updated
  • Loading branch information
sepandhaghighi authored Aug 12, 2024
1 parent b8f1fef commit 0d81ddf
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 31 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Changed
- `engine` parameter added to `play` function
- `README.md` modified
- `__play_win` function renamed to `__play_winsound`
- `__play_mac` function renamed to `__play_afplay`
- `__play_linux` function renamed to `__play_alsa`
## [0.6] - 2024-06-05
### Added
- `play_cli` function
Expand Down
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,32 +130,45 @@ except NavaBaseError as e:
print(str(e))
```

### Engine

⚠️ The `engine` parameter has a default value of `AUTO`

```python
from nava import play, Engine
sound_id = play("alarm.wav", engine=Engine.AFPLAY)
```

### CLI
```bash
$ nava [--file FILE_PATH] [--loop] FILE_PATH
```

## Engine
## Engines list

List of different platforms and the corresponding engines that are used for sound playing.

<table>
<tr>
<th align="center">Platform</th>
<th align="center">Engine</th>
<th align="center">Platform</th>
<th align="center">References</th>
<th align="center">Supported Formats</th>
</tr>
<tr>
<td align="center"><code>ALSA</code></td>
<td align="center">Linux</td>
<td align="center"><a href="https://www.alsa-project.org/wiki/Main_Page">Advanced Linux Sound Architecture</a></td>
<td align="center"><code>.wav</code></td>
</tr>
<tr>
<td align="center"><code>WINSOUND</code></td>
<td align="center">Windows</td>
<td align="center"><a href="https://docs.python.org/3/library/winsound.html">Winsound</a></td>
<td align="center"><code>.wav</code></td>
</tr>
<tr>
<td align="center"><code>AFPLAY</code></td>
<td align="center">macOS</td>
<td align="center"><a href="https://ss64.com/mac/afplay.html">Audio File Play</a></td>
<td align="center"><code>.wav</code>,<code>.mp3</code></td>
Expand Down
2 changes: 1 addition & 1 deletion nava/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
"""Nava modules."""
from .params import NAVA_VERSION
from .params import NAVA_VERSION, Engine
from .errors import NavaBaseError
from .functions import play, stop, stop_all
import atexit
Expand Down
80 changes: 52 additions & 28 deletions nava/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
import shlex
from functools import wraps
from .thread import NavaThread
from .params import OVERVIEW
from .params import SOUND_FILE_PLAY_ERROR, SOUND_FILE_EXIST_ERROR
from .params import OVERVIEW, Engine
from .params import SOUND_FILE_PLAY_ERROR, SOUND_FILE_EXIST_ERROR, ENGINE_TYPE_ERROR
from .params import SOUND_FILE_PATH_TYPE_ERROR, SOUND_ID_EXIST_ERROR, LOOP_ASYNC_ERROR
from .errors import NavaBaseError
from . import params
Expand Down Expand Up @@ -82,9 +82,9 @@ def quoter(sound_path, *args, **kwargs):
return quoter


def __play_win(sound_path, async_mode=False, loop=False):
def __play_winsound(sound_path, async_mode=False, loop=False):
"""
Play sound in Windows.
Play sound using the winsound library.
:param sound_path: sound path
:type sound_path: str
Expand All @@ -103,20 +103,20 @@ def __play_win(sound_path, async_mode=False, loop=False):

if async_mode:
sound_thread = NavaThread(loop,
target=__play_win_flags,
target=__play_winsound_flags,
args=(sound_path, play_flags),
daemon=True)
sound_thread.start()
sound_id = sound_id_gen()
params._play_threads_map[sound_id] = sound_thread
return sound_id
else:
__play_win_flags(sound_path, play_flags)
__play_winsound_flags(sound_path, play_flags)


def __play_win_flags(sound_path, flags):
def __play_winsound_flags(sound_path, flags):
"""
Play sound in Windows using different flags.
Play sound in winsound using different flags.
:param sound_path: sound path
:type sound_path: str
Expand All @@ -129,9 +129,9 @@ def __play_win_flags(sound_path, flags):


@quote
def __play_linux(sound_path, async_mode=False, loop=False):
def __play_alsa(sound_path, async_mode=False, loop=False):
"""
Play sound in Linux.
Play sound using ALSA.
:param sound_path: sound path to be played
:type sound_path: str
Expand All @@ -143,7 +143,7 @@ def __play_linux(sound_path, async_mode=False, loop=False):
"""
if async_mode:
sound_thread = NavaThread(loop,
target=__play_proc_linux,
target=__play_proc_alsa,
args=(sound_path,),
daemon=True)
sound_thread.start()
Expand All @@ -152,15 +152,15 @@ def __play_linux(sound_path, async_mode=False, loop=False):
return sound_id
else:
while True:
proc = __play_proc_linux(sound_path)
proc = __play_proc_alsa(sound_path)
proc.wait()
if not loop:
break


def __play_proc_linux(sound_path):
def __play_proc_alsa(sound_path):
"""
Create sound playing process in Linux.
Create sound playing process using ALSA.
:param sound_path: sound path to be played
:type sound_path: str
Expand All @@ -176,9 +176,9 @@ def __play_proc_linux(sound_path):


@quote
def __play_mac(sound_path, async_mode=False, loop=False):
def __play_afplay(sound_path, async_mode=False, loop=False):
"""
Play sound in macOS.
Play sound using afplay.
:param sound_path: sound path
:type sound_path: str
Expand All @@ -190,7 +190,7 @@ def __play_mac(sound_path, async_mode=False, loop=False):
"""
if async_mode:
sound_thread = NavaThread(loop,
target=__play_proc_mac,
target=__play_proc_afplay,
args=(sound_path,),
daemon=True)
sound_thread.start()
Expand All @@ -199,15 +199,15 @@ def __play_mac(sound_path, async_mode=False, loop=False):
return sound_id
else:
while True:
proc = __play_proc_mac(sound_path)
proc = __play_proc_afplay(sound_path)
proc.wait()
if not loop:
break


def __play_proc_mac(sound_path):
def __play_proc_afplay(sound_path):
"""
Create sound playing process in macOS.
Create sound playing process using afplay.
:param sound_path: sound path to be played
:type sound_path: str
Expand Down Expand Up @@ -249,9 +249,28 @@ def path_checker(sound_path, *args, **kwargs):
return func(sound_path, *args, **kwargs)
return path_checker

def __play_auto(sound_path, async_mode=False, loop=False):
"""
Play sound in automatic mode.
:param sound_path: sound path
:type sound_path: str
:param async_mode: async mode flag
:type async_mode: bool
:param loop: sound loop flag
:type loop: bool
:return: None or sound id
"""
sys_platform = sys.platform
if sys_platform == "win32":
return __play_winsound(sound_path, async_mode, loop)
elif sys_platform == "darwin":
return __play_afplay(sound_path, async_mode, loop)
else:
return __play_alsa(sound_path, async_mode, loop)

@path_check
def play(sound_path, async_mode=False, loop=False):
def play(sound_path, async_mode=False, loop=False, engine=Engine.AUTO):
"""
Play sound.
Expand All @@ -261,18 +280,23 @@ def play(sound_path, async_mode=False, loop=False):
:type async_mode: bool
:param loop: sound loop flag
:type loop: bool
:param engine: play engine
:type engine: Engine enum
:return: None or sound id
"""
if not isinstance(engine, Engine):
raise NavaBaseError(ENGINE_TYPE_ERROR)
if loop and not async_mode:
raise NavaBaseError(LOOP_ASYNC_ERROR)
try:
sys_platform = sys.platform
if sys_platform == "win32":
return __play_win(sound_path, async_mode, loop)
elif sys_platform == "darwin":
return __play_mac(sound_path, async_mode, loop)
else:
return __play_linux(sound_path, async_mode, loop)
if engine == Engine.AUTO:
return __play_auto(sound_path=sound_path, async_mode=async_mode, loop=loop)
elif engine == Engine.WINSOUND:
return __play_winsound(sound_path=sound_path, async_mode=async_mode, loop=loop)
elif engine == Engine.AFPLAY:
return __play_afplay(sound_path=sound_path, async_mode=async_mode, loop=loop)
elif engine == Engine.ALSA:
return __play_alsa(sound_path=sound_path, async_mode=async_mode, loop=loop)
except Exception: # pragma: no cover
raise NavaBaseError(SOUND_FILE_PLAY_ERROR)

Expand Down
15 changes: 15 additions & 0 deletions nava/params.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
"""Nava parameters."""
from enum import Enum

NAVA_VERSION = "0.6"

Expand All @@ -8,11 +9,25 @@
"""

class Engine(Enum):
"""
Nava engine class.
>>> import nava
>>> engine = nava.Engine.ALSA
"""

AUTO = "auto"
WINSOUND = "winsound"
ALSA = "alsa"
AFPLAY = "afplay"

SOUND_FILE_PLAY_ERROR = "Sound can not play due to some issues."
SOUND_FILE_EXIST_ERROR = "Given sound file doesn't exist."
SOUND_FILE_PATH_TYPE_ERROR = "Sound file's path should be a string."
SOUND_ID_EXIST_ERROR = "Given sound id doesn't exist."
LOOP_ASYNC_ERROR = "`loop` can not be set True when `async_mode` is False."
ENGINE_TYPE_ERROR = "`engine` type must be `Engine` enum."

_play_threads_map = dict()
_play_threads_counter = 0
4 changes: 4 additions & 0 deletions test/error_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
Traceback (most recent call last):
...
nava.errors.NavaBaseError: `loop` can not be set True when `async_mode` is False.
>>> play(os.path.join("others", "test.wav"), async_mode=True, loop=True, engine=2)
Traceback (most recent call last):
...
nava.errors.NavaBaseError: `engine` type must be `Engine` enum.
>>> import nava
>>> nava.functions.play_cli("test2.wav")
Error: Given sound file doesn't exist.
Expand Down
8 changes: 8 additions & 0 deletions test/function_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
"""
>>> import os
>>> import sys
>>> import time
>>> import nava
>>> nava.play(os.path.join("others", "test.wav"))
Expand All @@ -27,6 +28,13 @@
True
>>> nava.params._play_threads_counter == 44
True
>>> sys_platform = sys.platform
>>> if sys_platform == "win32":
... sound_id = nava.play(os.path.join("others", "test.wav"), async_mode=True, engine=nava.Engine.WINSOUND)
... elif sys_platform == "darwin":
... sound_id = nava.play(os.path.join("others", "test.wav"), async_mode=True, engine=nava.Engine.AFPLAY)
... else:
... sound_id = nava.play(os.path.join("others", "test.wav"), async_mode=True, engine=nava.Engine.ALSA)
>>> nava.functions.play_cli(os.path.join("others", "test.wav"))
>>> nava.functions.nava_help()
<BLANKLINE>
Expand Down

0 comments on commit 0d81ddf

Please sign in to comment.