reprostim.audio.audiocodes

Audiocodes module for reprostim, provides functionality to generate and parse QR-like audiocodes to be included in psychopy based scripts.

Functions

beep([duration, async_])

Play a beep sound for the given duration.

bit_enumerator(data)

Enumerate audio data bits.

bits_to_bytes(detected_bits)

Convert a list of bits (0 and 1) into a bytes object.

crc8(data[, polynomial, init_value])

Compute the CRC-8 checksum for a given byte sequence.

list_audio_devices()

List all available audio devices.

play_audio(name[, duration, volume, ...])

Play an audio file with specified parameters.

save_audiocode([fname, code_uint16, ...])

Save an audiocode to a file (*.wav).

Classes

AudioCodeEngine([codec, f0, f1, nfe_df, ...])

Class to generate and parse QR-like audiocodes with Frequency Shift Keying (FSK) or Numerical Frequency Encoding (NFE) modulations.

AudioCodeInfo()

Class to provide general information about an audiocode.

AudioCodec(value)

Enum for audio codecs constants.

AudioLib(value)

Enum for the audio libs constants.

DataMessage()

Class representing an audio data message in big-endian format, encoded with Reed-Solomon error correction.

class reprostim.audio.audiocodes.AudioCodeEngine(codec=AudioCodec.FSK, f0=1000, f1=5000, nfe_df=100, sample_rate=44100, bit_duration=0.007, nfe_duration=0.5, volume=0.8, pre_delay=0.1, pre_f=0, post_delay=0.1, post_f=0)[source]

Class to generate and parse QR-like audiocodes with Frequency Shift Keying (FSK) or Numerical Frequency Encoding (NFE) modulations.

This class handles the encoding and decoding of audio data using FSK or NFE modulation schemes, where data is represented as special audio tones.

Parameters:
  • codec (AudioCodec) – The codec used for encoding the audio data. Defaults to AudioCodec.FSK.

  • f0 (int) – The frequency for representing a binary 0 in FSK modulation. Defaults to 1000 Hz.

  • f1 (int) – The frequency for representing a binary 1 in FSK modulation. Defaults to 5000 Hz.

  • nfe_df (int) – The frequency difference used for Numerical Frequency Encoding (NFE). Defaults to 100 Hz.

  • sample_rate (int) – The sample rate used for audio generation. Defaults to 44100 Hz.

  • bit_duration (float) – The duration of each bit in FSK modulation. Defaults to 0.0070 seconds.

  • nfe_duration (float) – The duration for each frequency in NFE encoding. Defaults to 0.5 seconds.

  • volume (float) – The volume level for the audio output. Defaults to 0.80.

  • pre_delay (float) – The pre-delay before the audio signal starts. Defaults to 0.1 seconds.

  • pre_f (int) – The frequency before the start of the tone in FSK encoding. Defaults to 0 Hz (1780 Hz).

  • post_delay (float) – The post-delay after the audio signal ends. Defaults to 0.1 seconds.

  • post_f (int) – The frequency after the end of the tone in FSK encoding. Defaults to 0 Hz (3571 Hz).

generate(data) -> (<built-in function array>, <class 'reprostim.audio.audiocodes.AudioCodeInfo'>)[source]

Generates an audio signal based on the specified codec and provided data.

This method selects the appropriate encoding method based on the codec and generates the corresponding audio signal. Currently supports FSK and NFE encodings.

Parameters:

data (str | bytes | int) – The data to be encoded into the audio signal. The format of the data depends on the selected codec.

Returns:

A tuple containing the generated audio signal and related audiocode information.

Return type:

tuple(np.ndarray, AudioCodeInfo)

Raises:

ValueError – If the codec is not supported.

Example

>>> engine = AudioCodeEngine(codec=AudioCodec.FSK)
>>> signal, info = engine.generate("Hello")
generate_fsk(data) -> (<built-in function array>, <class 'reprostim.audio.audiocodes.AudioCodeInfo'>)[source]

Generates FSK audio signal from the given data.

Parameters:

data (str | bytes | int) – The data to be encoded into the FSK signal. This could be a string, bytes, or int.

Returns:

A tuple with FSK audio signal and related audiocode information.

Return type:

tuple(np.ndarray, AudioCodeInfo)

generate_nfe(data) -> (<built-in function array>, <class 'reprostim.audio.audiocodes.AudioCodeInfo'>)[source]

Generates NFE audio signal from the given data.

Parameters:

data (str | bytes | int) – The data to be encoded into the NFE signal. This could be a string, bytes, or int.

Returns:

A tuple with NFE audio signal and related audiocode information.

Return type:

tuple(np.ndarray, AudioCodeInfo)

generate_sin(freq_hz, duration_sec)[source]

Generates a sine wave audio signal with a specified frequency and duration.

Parameters:
  • freq_hz (float) – The frequency of the sine wave in Hz.

  • duration_sec (float) – The duration of the sine wave signal in seconds.

Returns:

A numpy array representing the generated sine wave audio signal.

Return type:

numpy.ndarray

parse(filename)[source]

Parses the audiocode file to detect and decode stored data.

Parameters:

filename (str) – The name of the *.wav file to parse.

Returns:

The decoded data as bytes.

Return type:

bytes

Raises:

ValueError – If audiocode is not possible to parse nor decode.

Example

>>> engine = AudioCodeEngine()
>>> decoded_data = engine.parse("encoded_audio.wav")
play_data_sd(data)[source]

Plays the audio data using the sounddevice library.

This method generates an audio signal based on the provided data and plays it using the sounddevice library.

Parameters:

data (str | bytes | int) – The data to be encoded into the audio signal and played.

Returns:

None

Example:
>>> engine = AudioCodeEngine()
>>> engine.play_data_sd("Hello")
save(data, filename)[source]

Generates and saves the audio signal to *.wav file.

Parameters:
  • data (str | bytes | int) – The data to be encoded into the audio signal.

  • filename (str) – The name of the *.wav file where the signal will be saved.

Returns:

The AudioCodeInfo object containing information about the saved audiocode.

Return type:

AudioCodeInfo

Example

>>> engine = AudioCodeEngine()
>>> engine.save("Hello", "output.wav")
class reprostim.audio.audiocodes.AudioCodeInfo[source]

Class to provide general information about an audiocode.

bit_count

The number of bits in the encoded data.

bit_duration

Bit duration in seconds for FSK audiocode.

codec

The codec used for the audiocode (e.g., FSK, NFE).

duration

The total duration of the audio signal in seconds.

f0

The frequency corresponding to logic 0 in FSK modulation.

f1

The frequency corresponding to logic 1 in FSK modulation.

nfe_df

Frequency difference in Hz used by NFE codec.

nfe_duration

Duration of NFE signal in seconds.

nfe_freq

Frequency for NFE modulation when this codec is used.

post_delay

Post-delay time after the audio code ends in seconds.

pre_delay

Pre-delay time before the audio code starts in seconds.

sample_rate

The sample rate of the audio signal

volume

The volume level of the audio signal on range 0..1 .

class reprostim.audio.audiocodes.AudioCodec(value)[source]

Enum for audio codecs constants.

FSK = 'FSK'

Frequency Shift Keying (FSK), where binary data is encoded as two different frequencies (f0 and f1) with a fixed bit duration (baud rate or bit_rate).

NFE = 'NFE'

Numerical Frequency Encoding (NFE), where numbers are mapped directly to specific frequencies. This codec can encode only certain numeric hash values.

class reprostim.audio.audiocodes.AudioLib(value)[source]

Enum for the audio libs constants.

PSYCHOPY_PTB = 'psychopy_ptb'

PsychoPy SoundPTB audio lib

PSYCHOPY_SOUNDDEVICE = 'psychopy_sounddevice'

PsychoPy SoundDevice audio lib

SOUNDDEVICE = 'sounddevice'

sounddevice audio lib, see more at: http://python-sounddevice.readthedocs.io/

class reprostim.audio.audiocodes.DataMessage[source]

Class representing an audio data message in big-endian format, encoded with Reed-Solomon error correction.

The message is structured as follows: - 1st byte: CRC-8 checksum - 2nd byte: Length of the data - 3rd byte onward: The data itself

decode(data: bytes)[source]

Decodes the given data bytes, verifying the CRC-8 checksum and parsing the length and data. If error correction is enabled, Reed-Solomon error correction is applied to the data before decoding.

Parameters:

data (bytes) – The encoded byte data to decode, including the CRC-8 checksum and length.

Raises:

ValueError – If the CRC-8 checksum does not match the computed checksum of the data.

encode() bytes[source]

Encodes the data message, including the CRC-8 checksum and length, and applies Reed-Solomon error correction if enabled. Returns the encoded byte sequence.

Returns:

The encoded byte sequence with the CRC-8 checksum, length, and optionally Reed-Solomon error correction.

Return type:

bytes

get_bytes() bytes[source]

Returns the data value as a bytes object.

Returns:

The data stored in the message.

Return type:

bytes

get_str() str[source]

Returns the data value as a UTF-8 decoded string.

Returns:

The decoded string from the message data.

Return type:

str

get_uint() int[source]

Returns the stored data as an unsigned integer.

Decodes the data based on its length (2, 4, or 8 bytes) and returns it as either a uint16, uint32, or uint64.

Returns:

The decoded unsigned integer.

Return type:

int

Raises:

ValueError – If the data length is not 2, 4, or 8 bytes.

get_uint16() int[source]

Returns the stored data as a 16-bit unsigned integer (uint16).

The method assumes the data length is exactly 2 bytes. If the length is not 2, a ValueError is raised.

Returns:

The decoded 16-bit unsigned integer.

Return type:

int

Raises:

ValueError – If the data length is not 2 bytes.

get_uint32() int[source]

Returns the stored data as a 32-bit unsigned integer (uint32).

The method assumes the data length is exactly 4 bytes. If the length is not 4, a ValueError is raised.

Returns:

The decoded 32-bit unsigned integer.

Return type:

int

Raises:

ValueError – If the data length is not 4 bytes.

get_uint64() int[source]

Returns the stored data as a 64-bit unsigned integer (uint64).

The method assumes the data length is exactly 8 bytes. If the length is not 8, a ValueError is raised.

Returns:

The decoded 64-bit unsigned integer.

Return type:

int

Raises:

ValueError – If the data length is not 8 bytes.

set_bytes(data: bytes)[source]

Sets the bytes data value.

Parameters:

data (bytes) – The data to be stored in the message.

set_str(s: str)[source]

Sets the string data value.

Parameters:

s (str) – The string to be stored in the message.

set_uint16(i: int)[source]

Sets the 16-bit unsigned integer data value.

Parameters:

i (int) – The uint16 to be stored in the message.

set_uint32(i: int)[source]

Sets the 32-bit unsigned integer data value.

Parameters:

i (int) – The uint32 to be stored in the message.

set_uint64(i: int)[source]

Sets the 64-bit unsigned integer data value.

Parameters:

i (int) – The uint64 to be stored in the message.

reprostim.audio.audiocodes.beep(duration: float = 2.0, async_: bool = False)[source]

Play a beep sound for the given duration.

Parameters:
  • duration (float) – The duration of the beep in seconds. Default is 2.0 seconds.

  • async (bool) – If True, play the sound asynchronously. Default is False.

reprostim.audio.audiocodes.bit_enumerator(data)[source]

Enumerate audio data bits.

This function takes either a string representation of binary digits (0 and 1) or a bytes object and yields individual bits as integers (0 or 1).

Parameters:

data (str | bytes | DataMessage) – The input data containing bits.

Yield:

The extracted bits as integers (0 or 1).

Return type:

int

Raises:
  • ValueError – If a string contains characters other than 0 and 1.

  • TypeError – If the input data type is not supported.

reprostim.audio.audiocodes.bits_to_bytes(detected_bits)[source]

Convert a list of bits (0 and 1) into a bytes object.

This function takes a list of bits, groups them into bytes (8 bits each), and converts them into a bytes object in big-endian order.

Parameters:

detected_bits (list of int) – A list containing only 0 and 1. The length of the list must be a multiple of 8.

Returns:

A bytes object representing the converted bit sequence.

Return type:

bytes

Raises:

ValueError – If the length of detected_bits is not a multiple of 8.

Example

>>> bits_to_bytes([1, 0, 0, 0, 0, 0, 0, 1])
b'\x81'
reprostim.audio.audiocodes.crc8(data: bytes, polynomial: int = 49, init_value: int = 0) int[source]

Compute the CRC-8 checksum for a given byte sequence.

Parameters:
  • data (bytes) – The input data for which to compute the CRC-8 checksum.

  • polynomial (int, optional) – Polynomial to calculate CRC (default: 0x31).

  • init_value (int, optional) – The initial CRC value (default: 0x00).

Returns:

The computed 8-bit CRC checksum.

Return type:

int

Example

>>> crc8(b"123456789")
b'\0xA2'
>>> crc8(b"Hello", polynomial=0x07, init_value=0xFF)
b'\0xFC'
reprostim.audio.audiocodes.list_audio_devices()[source]

List all available audio devices.

This function queries and logs available audio devices from different libraries (psychopy, sounddevice, psytoolbox, and psychopy.backend_ptb), and logs the current default input and output devices.

The function does not return any value but logs detailed information about each device to the standard logger.

Returns:

None

Return type:

None

Raises:

None

Example

>>> list_audio_devices()
# Logs detailed information about available audio devices
reprostim.audio.audiocodes.play_audio(name: str, duration: float | None = None, volume: float = 0.8, sample_rate: int = 44100, async_: bool = False)[source]

Play an audio file with specified parameters.

This function plays an audio file using the specified audio library. It supports different libraries such as PsychoPy (using Sounddevice or PTB) and Sounddevice.

Parameters:
  • name (str) – The name of the audio file to play.

  • duration (float, optional) – The duration (in seconds) for which to play the audio. If not specified, the audio will play in its entirety.

  • volume (float, optional) – The volume level to set for the audio. Should be a value between 0.0 and 1.0, where 1.0 is the maximum volume. Default is 0.8.

  • sample_rate (int, optional) – The sample rate (in Hz) for the audio playback. Default is 44100.

  • async (bool, optional) – Whether to play the audio asynchronously. If set to True, the audio will play in the background. Default is False.

Raises:

ValueError – If the selected audio library is unsupported.

Example

>>> play_audio("sound.wav", duration=5, volume=0.5)
# Plays the audio file "sound.wav" for 5 seconds at half-volume.
reprostim.audio.audiocodes.save_audiocode(fname: str | None = None, code_uint16: int | None = None, code_uint32: int | None = None, code_uint64: int | None = None, code_str: str | None = None, code_bytes: bytes | None = None, code_duration: float = 0.5, codec: ~reprostim.audio.audiocodes.AudioCodec = AudioCodec.FSK, engine=None) -> (<class 'str'>, <class 'reprostim.audio.audiocodes.AudioCodeInfo'>)[source]

Save an audiocode to a file (*.wav).

This function saves an audiocode to a file using the specified encoding engine and codec. The code can be provided in various formats, such as unsigned integers (16, 32, 64 bits), a string, or bytes.

Parameters:
  • fname (str, optional) – The name of the file where the audio code will be saved. If not provided, a temporary filename is generated.

  • code_uint16 (int, optional) – The audio code as a 16-bit unsigned integer.

  • code_uint32 (int, optional) – The audio code as a 32-bit unsigned integer.

  • code_uint64 (int, optional) – The audio code as a 64-bit unsigned integer.

  • code_str (str, optional) – The audio code as a string.

  • code_bytes (float, optional) – The audio code as bytes.

  • code_duration – The duration of the audio code in seconds, used only for NFE codec ATM. Default is 0.5 seconds.

  • codec (AudioCodec, optional) – The audio codec to use for encoding the audio code. Default is AudioCodec.FSK.

  • engine (AudioCodeEngine, optional) – The encoding engine to use. If not specified, an AudioCodeEngine is created using the provided codec.

Returns:

A tuple containing the file name where the audio code was saved and the corresponding AudioCodeInfo object.

Return type:

tuple of (str, AudioCodeInfo)

Raises:

ValueError – If no code data is provided.

Example

>>> save_audiocode(fname="code.wav", code_uint16=12345)
('code.wav', <AudioCodeInfo object>)