Skip to content
This repository has been archived by the owner on Apr 20, 2024. It is now read-only.

Commit

Permalink
explicitly set data types for input args and outputs of methods and f…
Browse files Browse the repository at this point in the history
…unctions
  • Loading branch information
MGTheTrain committed Apr 17, 2024
1 parent 814dd20 commit 128886d
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 36 deletions.
73 changes: 43 additions & 30 deletions bindings/python/audio_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,16 @@
# SOFTWARE.

import ctypes
import pyaudio

class AudioWrapper:
"""
A wrapper class for an audio library implemented in C/C++ using ctypes.
Attributes:
audio_lib (CDLL): The loaded audio library.
pyaudio (PyAudio): PyAudio instance.
audio_callback (PyAudio callback): The callback function for audio playback.
"""

def __init__(self, path: str):
Expand All @@ -38,6 +41,8 @@ def __init__(self, path: str):
path (str): The path to the audio library.
"""
self.audio_lib = ctypes.cdll.LoadLibrary(path)
self.pyaudio = pyaudio.PyAudio()
self.audio_callback = self._audio_callback # Set the callback function for audio playback

self.audio_lib.loadAudioFile.argtypes = [ctypes.c_char_p, ctypes.POINTER(AudioData)]
self.audio_lib.loadAudioFile.restype = ctypes.c_bool
Expand All @@ -53,7 +58,26 @@ def __init__(self, path: str):
ctypes.c_int, ctypes.c_void_p]
self.audio_lib.playbackCallback.restype = ctypes.c_int

def load_audio_file(self, filename, audio_data):
def _audio_callback(self, in_data, frame_count, time_info, status):
"""
PyAudio callback function for audio playback.
This function is called by PyAudio when it needs more audio data to play.
Args:
in_data: Input audio data (not used in playback).
frame_count (int): Number of frames requested for playback.
time_info (dict): Timing information for the callback.
status (int): Status flags indicating possible errors or other information.
Returns:
tuple: A tuple containing the audio data and a flag indicating whether playback is complete.
"""
audio_data = ctypes.create_string_buffer(frame_count * ctypes.sizeof(ctypes.c_float))
status = self.audio_lib.playbackCallback(None, audio_data, frame_count, None, 0, None)
return audio_data.raw, pyaudio.paContinue if status == 0 else pyaudio.paComplete

def load_audio_file(self, filename: str, audio_data: ctypes.POINTER(AudioData)) -> bool:
"""
Load an audio file using the audio library.
Expand All @@ -66,7 +90,7 @@ def load_audio_file(self, filename, audio_data):
"""
return self.audio_lib.loadAudioFile(filename.encode('utf-8'), ctypes.byref(audio_data))

def start_playback(self, audio_data):
def start_playback(self, audio_data: ctypes.POINTER(AudioData)) -> bool:
"""
Start playback of the loaded audio file using the audio library.
Expand All @@ -76,16 +100,28 @@ def start_playback(self, audio_data):
Returns:
bool: True if playback was successfully started, False otherwise.
"""
return self.audio_lib.startPlayback(ctypes.byref(audio_data))

def close_audio_file(self, audio_data):
stream = self.pyaudio.open(
format=self.pyaudio.get_format_from_width(4), # 4 bytes per float
channels=audio_data.info.channels,
rate=audio_data.info.samplerate,
output=True,
stream_callback=self.audio_callback
)
stream.start_stream()
return True

def close_audio_file(self, audio_data: ctypes.POINTER(AudioData)):
"""
Close the loaded audio file using the audio library.
Args:
audio_data (AudioData): The AudioData structure containing the audio data to close.
"""
return self.audio_lib.closeAudioFile(ctypes.byref(audio_data))
# Close the PyAudio stream
self.pyaudio.terminate()
# Close the audio file using the audio library
self.audio_lib.closeAudioFile(ctypes.byref(audio_data))


class SF_INFO(ctypes.Structure):
"""
Expand Down Expand Up @@ -139,29 +175,6 @@ class PaStreamCallbackTimeInfo(ctypes.Structure):
("outputBufferDacTime", ctypes.c_double)
]


class SF_INFO(ctypes.Structure):
"""
Structure to hold information about an audio file.
Attributes:
frames (c_int): Total frames.
samplerate (c_int): Sample rate.
channels (c_int): Number of channels.
format (c_int): Format of the audio data.
sections (c_int): Sections.
seekable (c_int): Seekable flag.
"""
_fields_ = [
("frames", ctypes.c_int),
("samplerate", ctypes.c_int),
("channels", ctypes.c_int),
("format", ctypes.c_int),
("sections", ctypes.c_int),
("seekable", ctypes.c_int)
]


def playback_callback(input, output, frame_count, time_info, status_flags, user_data):
"""
Callback function for audio playback.
Expand All @@ -179,4 +192,4 @@ def playback_callback(input, output, frame_count, time_info, status_flags, user_
Returns:
int: paContinue if playback should continue, paComplete if playback is complete.
"""
return AudioWrapper().audio_lib.playbackCallback(input, output, frame_count, ctypes.byref(time_info), status_flags, user_data)
return AudioWrapper().audio_lib.playbackCallback(input, output, frame_count, ctypes.byref(time_info), status_flags, user_data)
13 changes: 7 additions & 6 deletions bindings/python/core_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def __init__(self, path: str):
self.core_lib.getCircleCircumference.restype = ctypes.c_float
self.core_lib.getCircleCircumference.argtypes = [ctypes.c_float]

def add(self, a, b):
def add(self, a: int, b: int) -> int:
"""
Add two integers using the core library.
Expand All @@ -69,7 +69,7 @@ def add(self, a, b):
"""
return self.core_lib.add(a, b)

def subtract(self, a, b):
def subtract(self, a: int, b: int) -> int:
"""
Subtract two integers using the core library.
Expand All @@ -82,7 +82,7 @@ def subtract(self, a, b):
"""
return self.core_lib.subtract(a, b)

def multiply(self, a, b):
def multiply(self, a: int, b: int) -> int:
"""
Multiply two integers using the core library.
Expand All @@ -95,7 +95,7 @@ def multiply(self, a, b):
"""
return self.core_lib.multiply(a, b)

def divide(self, a, b):
def divide(self, a: float, b: float) -> float:
"""
Divide two floats using the core library.
Expand All @@ -108,7 +108,7 @@ def divide(self, a, b):
"""
return self.core_lib.divide(a, b)

def get_circle_area(self, radius):
def get_circle_area(self, radius: float) -> float:
"""
Calculate the area of a circle using the core library.
Expand All @@ -120,7 +120,7 @@ def get_circle_area(self, radius):
"""
return self.core_lib.getCircleArea(radius)

def get_circle_circumference(self, radius):
def get_circle_circumference(self, radius: float) -> float:
"""
Calculate the circumference of a circle using the core library.
Expand All @@ -131,3 +131,4 @@ def get_circle_circumference(self, radius):
float: The circumference of the circle.
"""
return self.core_lib.getCircleCircumference(radius)

0 comments on commit 128886d

Please sign in to comment.