Module audioio.audiometadata

Working with metadata.

To interface the various ways metadata are stored in audio files, the audioio package uses nested dictionaries. The keys are always strings. Values are strings, integers, floats, datetimes, or other types. Value strings can also be numbers followed by a unit, e.g. "4.2mV". For defining subsections of key-value pairs, values can be dictionaries. The dictionaries can be nested to arbitrary depth.

>>> from audioio import print_metadata
>>> md = dict(Recording=dict(Experimenter='John Doe',
                             DateTimeOriginal='2023-10-01T14:10:02',
                             Count=42),
               Hardware=dict(Amplifier='Teensy_Amp 4.1',
                             Highpass='10Hz',
                             Gain='120mV'))
>>> print_metadata(md)
Recording:
    Experimenter    : John Doe
    DateTimeOriginal: 2023-10-01T14:10:02
    Count           : 42
Hardware:
    Amplifier: Teensy_Amp 4.1
    Highpass : 10Hz
    Gain     : 120mV

Often, audio files have very specific ways to store metadata. You can enforce using these by putting them into a dictionary that is added to the metadata with a key having the name of the metadata type you want, e.g. the "INFO", "BEXT", "iXML", and "GUAN" chunks of RIFF/WAVE files.

Functions

The audiometadata module provides functions for handling and manipulating these nested dictionaries. Many functions take keys as arguments for finding or setting specific key-value pairs. These keys can be the key of a specific item of a (sub-) dictionary, no matter on which level of the metadata hierarchy it is. For example, simply searching for "Highpass" retrieves the corrseponding value "10Hz", although "Highpass" is contained in the sub-dictionary (or "section") with key "Hardware". The same item can also be specified together with its parent keys: "Hardware.Highpass". Parent keys (or section keys) are by default separated by '.', but all functions have a sep key-word that specifies the string separating section names in keys. Key matching is case insensitive.

Since the same items are named by many different keys in the different types of metadata data models, the functions also take lists of keys as arguments.

Do not forget that you can easily manipulate the metadata by means of the standard functions of dictionaries.

If you need to make a copy of the metadata use deepcopy:

from copy import deepcopy
md_orig = deepcopy(md)

Output

Write nested dictionaries as texts:

Flatten

Conversion between nested and flat dictionaries:

Parse numbers with units

Find and get values

Find keys and get their values parsed and converted to various types:

  • find_key(): find dictionary in metadata hierarchy containing the specified key.
  • get_number_unit(): find a key in metadata and return its number and unit.
  • get_number(): find a key in metadata and return its value in a given unit.
  • get_int(): find a key in metadata and return its integer value.
  • get_bool(): find a key in metadata and return its boolean value.
  • get_datetime(): find keys in metadata and return a datatime.
  • get_str(): find a key in metadata and return its string value.

Organize metadata

Add and remove metadata:

Special metadata fields

Retrieve and set specific metadata:

Lists of standard keys:

Command line script

The module can be run as a script from the command line to display the metadata and markers contained in an audio file:

> audiometadata logger.wav

prints

file:
  filepath    : logger.wav
  samplingrate: 96000Hz
  channels    : 16
  frames      : 17280000
  duration    : 180.000s

metadata:
  INFO:
      Bits            : 32
      Pins            : 1-CH2R,1-CH2L,1-CH3R,1-CH3L,2-CH2R,2-CH2L,2-CH3R,2-CH3L,3-CH2R,3-CH2L,3-CH3R,3-CH3L,4-CH2R,4-CH2L,4-CH3R,4-CH3L
      Gain            : 165.00mV
      uCBoard         : Teensy 4.1
      MACAdress       : 04:e9:e5:15:3e:95
      DateTimeOriginal: 2023-10-01T14:10:02
      Software        : TeeGrid R4-senors-logger v1.0

Alternatively, the script can be run from the module as:

python -m src.audioio.metadata audiofile.wav

Running

audiometadata --help

prints

usage: audiometadata [-h] [--version] [-f] [-m] [-c] [-t] files [files ...]

Convert audio file formats.

positional arguments:
  files       audio file

options:
  -h, --help  show this help message and exit
  --version   show program's version number and exit
  -f          list file format only
  -m          list metadata only
  -c          list cues/markers only
  -t          list tags of all riff/wave chunks contained in the file

version 2.0.0 by Benda-Lab (2020-2024)

Global variables

var unit_prefixes

SI prefixes for units with corresponding factors.

var default_starttime_keys

Default keys of times of start of the recording in metadata. Used by get_datetime() and update_starttime() functions.

var default_gain_keys

Default keys of gain settings in metadata. Used by get_gain() function.

var default_timeref_keys

Default keys of integer time references in metadata. Used by update_starttime() function.

var default_history_keys

Default keys of strings describing coding history in metadata. Used by add_history() function.

Functions

def write_metadata_text(fh, meta, prefix='', indent=4, replace=None)

Write meta data into a text/yaml file or stream.

With the default parameters, the output is a valid yaml file.

Parameters

fh : filename or stream
If not a stream, the file with name fh is opened. Otherwise fh is used as a stream for writing.
meta : nested dict
Key-value pairs of metadata to be written into the file.
prefix : str
This string is written at the beginning of each line.
indent : int
Number of characters used for indentation of sections.
replace : char or None
If specified, replace special characters by this character.

Examples

from audioio import write_metadata
md = dict(aaaa=2, bbbb=dict(ccc=3, ddd=4, eee=dict(hh=5)))
write_metadata('info.txt', md)
def print_metadata(meta, prefix='', indent=4, replace=None)

Write meta data to standard output.

Parameters

meta : nested dict
Key-value pairs of metadata to be written into the file.
prefix : str
This string is written at the beginning of each line.
indent : int
Number of characters used for indentation of sections.
replace : char or None
If specified, replace special characters by this character.

Examples

>>> from audioio import print_metadata
>>> md = dict(aaaa=2, bbbb=dict(ccc=3, ddd=4, eee=dict(hh=5)), iiii=dict(jjj=6))
>>> print_metadata(md)
aaaa: 2
bbbb:
    ccc: 3
    ddd: 4
    eee:
        hh: 5
iiii:
    jjj: 6
def flatten_metadata(md, keep_sections=False, sep='.')

Flatten hierarchical metadata to a single dictionary.

Parameters

md : nested dict
Metadata as returned by metadata().
keep_sections : bool
If True, then prefix keys with section names, separated by sep.
sep : str
String for separating section names.

Returns

d : dict
Non-nested dict containing all key-value pairs of md.

Examples

>>> from audioio import print_metadata, flatten_metadata
>>> md = dict(aaaa=2, bbbb=dict(ccc=3, ddd=4, eee=dict(hh=5)), iiii=dict(jjj=6))
>>> print_metadata(md)
aaaa: 2
bbbb:
    ccc: 3
    ddd: 4
    eee:
        hh: 5
iiii:
    jjj: 6

>>> fmd = flatten_metadata(md, keep_sections=True)
>>> print_metadata(fmd)
aaaa       : 2
bbbb.ccc   : 3
bbbb.ddd   : 4
bbbb.eee.hh: 5
iiii.jjj   : 6
def unflatten_metadata(md, sep='.')

Unflatten a previously flattened metadata dictionary.

Parameters

md : dict
Flat dictionary with key-value pairs as obtained from flatten_metadata() with keep_sections=True.
sep : str
String that separates section names.

Returns

d : nested dict
Hierarchical dictionary with sub-dictionaries and key-value pairs.

Examples

>>> from audioio import print_metadata, unflatten_metadata
>>> fmd = {'aaaa': 2, 'bbbb.ccc': 3, 'bbbb.ddd': 4, 'bbbb.eee.hh': 5, 'iiii.jjj': 6}
>>> print_metadata(fmd)
aaaa       : 2
bbbb.ccc   : 3
bbbb.ddd   : 4
bbbb.eee.hh: 5
iiii.jjj   : 6

>>> md = unflatten_metadata(fmd)
>>> print_metadata(md)
aaaa: 2
bbbb:
    ccc: 3
    ddd: 4
    eee:
        hh: 5
iiii:
    jjj: 6
def parse_number(s)

Parse string with number and unit.

Parameters

s : str, float, or int
String to be parsed. The initial part of the string is expected to be a number, the part following the number is interpreted as the unit. If float or int, then return this as the value with empty unit.

Returns

v : None, int, or float
Value of the string as float. Without decimal point, an int is returned. If the string does not contain a number, None is returned.
u : str
Unit that follows the initial number.
n : int
Number of digits behind the decimal point.

Examples

>>> from audioio import parse_number

# integer:
>>> parse_number('42')
(42, '', 0)

# integer with unit:
>>> parse_number('42ms')
(42, 'ms', 0)

# float with unit:
>>> parse_number('42.ms')
(42.0, 'ms', 0)

# float with unit:
>>> parse_number('42.3ms')
(42.3, 'ms', 1)

# float with space and unit:
>>> parse_number('423.17 Hz')
(423.17, 'Hz', 2)
def change_unit(val, old_unit, new_unit)

Scale numerical value to a new unit.

Adapted from https://github.com/relacs/relacs/blob/1facade622a80e9f51dbf8e6f8171ac74c27f100/options/src/parameter.cc#L1647-L1703

Parameters

val : float
Value given in old_unit.
old_unit : str
Unit of val.
new_unit : str
Requested unit of return value.

Returns

new_val : float
The input value val scaled to new_unit.

Examples

>>> from audioio import change_unit
>>> change_unit(5, 'mm', 'cm')
0.5

>>> change_unit(5, '', 'cm')
5.0

>>> change_unit(5, 'mm', '')
5.0

>>> change_unit(5, 'cm', 'mm')
50.0

>>> change_unit(4, 'kg', 'g')
4000.0

>>> change_unit(12, '%', '')
0.12

>>> change_unit(1.24, '', '%')
124.0

>>> change_unit(2.5, 'min', 's')
150.0

>>> change_unit(3600, 's', 'h')
1.0

def find_key(metadata, key, sep='.')

Find dictionary in metadata hierarchy containing the specified key.

Parameters

metadata : nested dict
Metadata.
key : str
Key to be searched for (case insensitive). May contain section names separated by sep, i.e. "aaa.bbb.ccc" searches "ccc" (can be key-value pair or section) in section "bbb" that needs to be a subsection of section "aaa".
sep : str
String that separates section names in key.

Returns

md : dict
The innermost dictionary matching some sections of the search key. If key is not at all contained in the metadata, the top-level dictionary is returned.
key : str
The part of the search key that was not found in md, or the the final part of the search key, found in md.

Examples

Independent of whether found or not found, you can assign to the returned dictionary with the returned key.

>>> from audioio import print_metadata, find_key
>>> md = dict(aaaa=2, bbbb=dict(ccc=3, ddd=4, eee=dict(ff=5)), gggg=dict(hhh=6))
>>> print_metadata(md)
aaaa: 2
bbbb:
    ccc: 3
    ddd: 4
    eee:
        ff: 5
gggg:
    hhh: 6

>>> m, k = find_key(md, 'bbbb.ddd')
>>> m[k] = 10
>>> print_metadata(md)
aaaa: 2
bbbb:
    ccc: 3
    ddd: 10
...

>>> m, k = find_key(md, 'hhh')
>>> m[k] = 12
>>> print_metadata(md)
...
gggg:
    hhh: 12

>>> m, k = find_key(md, 'bbbb.eee.xx')
>>> m[k] = 42
>>> print_metadata(md)
...
    eee:
        ff: 5
        xx: 42
...

When searching for sections, the one conaining the searched section is returned:

>>> m, k = find_key(md, 'eee')
>>> m[k]['yy'] = 46
>>> print_metadata(md)
...
    eee:
        ff: 5
        xx: 42
        yy: 46
...
def get_number_unit(metadata, keys, sep='.', default=None, default_unit='', remove=False)

Find a key in metadata and return its number and unit.

Parameters

metadata : nested dict
Metadata.
keys : str or list of str
Keys in the metadata to be searched for (case insensitive). Value of the first key found is returned. May contain section names separated by sep. See audiometadata.find_key() for details.
sep : str
String that separates section names in key.
default : None, int, or float
Returned value if key is not found or the value does not contain a number.
default_unit : str
Returned unit if key is not found or the key's value does not have a unit.
remove : bool
If True, remove the found key from metadata.

Returns

v : None, int, or float
Value referenced by key as float. Without decimal point, an int is returned. If none of the keys was found or the key`s value does not contain a number, then default is returned.
u : str
Corresponding unit.

Examples

>>> from audioio import get_number_unit
>>> md = dict(aaaa='42', bbbb='42.3ms')

# integer:
>>> get_number_unit(md, 'aaaa')
(42, '')

# float with unit:
>>> get_number_unit(md, 'bbbb')
(42.3, 'ms')

# two keys:
>>> get_number_unit(md, ['cccc', 'bbbb'])
(42.3, 'ms')

# not found:
>>> get_number_unit(md, 'cccc')
(None, '')

# not found with default value:
>>> get_number_unit(md, 'cccc', default=1.0, default_unit='a.u.')
(1.0, 'a.u.')
def get_number(metadata, unit, keys, sep='.', default=None, remove=False)

Find a key in metadata and return its value in a given unit.

Parameters

metadata : nested dict
Metadata.
unit : str
Unit in which to return numerical value referenced by one of the keys.
keys : str or list of str
Keys in the metadata to be searched for (case insensitive). Value of the first key found is returned. May contain section names separated by sep. See audiometadata.find_key() for details.
sep : str
String that separates section names in key.
default : None, int, or float
Returned value if key is not found or the value does not contain a number.
remove : bool
If True, remove the found key from metadata.

Returns

v : None or float
Value referenced by key as float scaled to unit. If none of the keys was found or the key`s value does not contain a number, then default is returned.

Examples

>>> from audioio import get_number
>>> md = dict(aaaa='42', bbbb='42.3ms')

# milliseconds to seconds:
>>> get_number(md, 's', 'bbbb')
0.0423

# milliseconds to microseconds:
>>> get_number(md, 'us', 'bbbb')
42300.0

# value without unit is not scaled:
>>> get_number(md, 'Hz', 'aaaa')
42

# two keys:
>>> get_number(md, 's', ['cccc', 'bbbb'])
0.0423

# not found:
>>> get_number(md, 's', 'cccc')
None

# not found with default value:
>>> get_number(md, 's', 'cccc', default=1.0)
1.0
def get_int(metadata, keys, sep='.', default=None, remove=False)

Find a key in metadata and return its integer value.

Parameters

metadata : nested dict
Metadata.
keys : str or list of str
Keys in the metadata to be searched for (case insensitive). Value of the first key found is returned. May contain section names separated by sep. See audiometadata.find_key() for details.
sep : str
String that separates section names in key.
default : None or int
Return value if key is not found or the value does not contain an integer.
remove : bool
If True, remove the found key from metadata.

Returns

v : None or int
Value referenced by key as integer. If none of the keys was found, the key's value does not contain a number or represents a floating point value, then default is returned.

Examples

>>> from audioio import get_int
>>> md = dict(aaaa='42', bbbb='42.3ms')

# integer:
>>> get_int(md, 'aaaa')
42

# two keys:
>>> get_int(md, ['cccc', 'aaaa'])
42

# float:
>>> get_int(md, 'bbbb')
None

# not found:
>>> get_int(md, 'cccc')
None

# not found with default value:
>>> get_int(md, 'cccc', default=0)
0
def get_bool(metadata, keys, sep='.', default=None, remove=False)

Find a key in metadata and return its boolean value.

Parameters

metadata : nested dict
Metadata.
keys : str or list of str
Keys in the metadata to be searched for (case insensitive). Value of the first key found is returned. May contain section names separated by sep. See audiometadata.find_key() for details.
sep : str
String that separates section names in key.
default : None or bool
Return value if key is not found or the value does not specify a boolean value.
remove : bool
If True, remove the found key from metadata.

Returns

v : None or bool
Value referenced by key as boolean. True if 'true', 'yes' (case insensitive) or any number larger than zero. False if 'false', 'no' (case insensitive) or any number equal to zero. If none of the keys was found or the key's value does specify a boolean value, then default is returned.

Examples

>>> from audioio import get_bool
>>> md = dict(aaaa='TruE', bbbb='No', cccc=0, dddd=1, eeee=True, ffff='ui')

# case insensitive:
>>> get_bool(md, 'aaaa')
True

>>> get_bool(md, 'bbbb')
False

>>> get_bool(md, 'cccc')
False

>>> get_bool(md, 'dddd')
True

>>> get_bool(md, 'eeee')
True

# not found:
>>> get_bool(md, 'ffff')
None

# two keys (string is preferred over number):
>>> get_bool(md, ['cccc', 'aaaa'])
True

# two keys (take first match):
>>> get_bool(md, ['cccc', 'ffff'])
False

# not found with default value:
>>> get_bool(md, 'ffff', default=False)
False
def get_datetime(metadata, keys=[['DateTimeOriginal'], ['OriginationDate', 'OriginationTime'], ['Location_Time'], ['Timestamp']], sep='.', default=None, remove=False)

Find keys in metadata and return a datatime.

Parameters

metadata : nested dict
Metadata.
keys : tuple of str or list of tuple of str
Datetimes can be stored in metadata as two separate key-value pairs, one for the date and one for the time. Or by a single key-value pair for a date-time values. This is why the keys need to be specified in tuples with one or tow keys. Value of the first tuple of keys found is returned. Keys may contain section names separated by sep. See audiometadata.find_key() for details. You can modify the default keys via the default_starttime_keys list of the audiometadata module.
sep : str
String that separates section names in key.
default : None or str
Return value if key is not found or the value does not contain a string.
remove : bool
If True, remove the found key from metadata.

Returns

v : None or datetime
Datetime referenced by keys. If none of the keys was found, then default is returned.

Examples

>>> from audioio import get_datetime
>>> import datetime as dt
>>> md = dict(date='2024-03-02', time='10:42:24',
              datetime='2023-04-15T22:10:00')

# separate date and time:
>>> get_datetime(md, ('date', 'time'))
datetime.datetime(2024, 3, 2, 10, 42, 24)

# single datetime:
>>> get_datetime(md, ('datetime',))
datetime.datetime(2023, 4, 15, 22, 10)

# two alternative key tuples:
>>> get_datetime(md, [('aaaa',), ('date', 'time')])
datetime.datetime(2024, 3, 2, 10, 42, 24)

# not found:
>>> get_datetime(md, ('cccc',))
None

# not found with default value:
>>> get_datetime(md, ('cccc', 'dddd'),
                 default=dt.datetime(2022, 2, 22, 22, 2, 12))
datetime.datetime(2022, 2, 22, 22, 2, 12)
def get_str(metadata, keys, sep='.', default=None, remove=False)

Find a key in metadata and return its string value.

Parameters

metadata : nested dict
Metadata.
keys : str or list of str
Keys in the metadata to be searched for (case insensitive). Value of the first key found is returned. May contain section names separated by sep. See audiometadata.find_key() for details.
sep : str
String that separates section names in key.
default : None or str
Return value if key is not found or the value does not contain a string.
remove : bool
If True, remove the found key from metadata.

Returns

v : None or str
String value referenced by key. If none of the keys was found, then default is returned.

Examples

>>> from audioio import get_str
>>> md = dict(aaaa=42, bbbb='hello')

# string:
>>> get_str(md, 'bbbb')
'hello'

# int as str:
>>> get_str(md, 'aaaa')
'42'

# two keys:
>>> get_str(md, ['cccc', 'bbbb'])
'hello'

# not found:
>>> get_str(md, 'cccc')
None

# not found with default value:
>>> get_str(md, 'cccc', default='-')
'-'
def add_sections(metadata, sections, value=False, sep='.')

Add sections to metadata dictionary.

Parameters

metadata : nested dict
Metadata.
key : str
Names of sections to be added to metadata. Section names separated by sep.
value : bool
If True, then the last element in key is a key for a value, not a section.
sep : str
String that separates section names in key.

Returns

md : dict
Dictionary of the last added section.
key : str
Last key. Only returned if value is set to True.

Examples

Add a section and a sub-section to the metadata:

>>> from audioio import print_metadata, add_sections
>>> md = dict()
>>> m = add_sections(md, 'Recording.Location')
>>> m['Country'] = 'Lummerland'
>>> print_metadata(md)
Recording:
    Location:
        Country: Lummerland

Add a section with a key-value pair:

>>> md = dict()
>>> m, k = add_sections(md, 'Recording.Location', True)
>>> m[k] = 'Lummerland'
>>> print_metadata(md)
Recording:
    Location: Lummerland

Adds well to find_key():

>>> md = dict(Recording=dict())
>>> m, k = find_key(md, 'Recording.Location.Country')
>>> m, k = add_sections(m, k, True)
>>> m[k] = 'Lummerland'
>>> print_metadata(md)
Recording:
    Location:
        Country: Lummerland
def strlist_to_dict(mds)

Convert list of key-value-pair strings to dictionary.

Parameters

mds : None or dict or str or list of str
  • None - returns empty dictionary.
  • Flat dictionary - returned as is.
  • String with key and value separated by '='.
  • List of strings with keys and values separated by '='. Keys may contain section names.

Returns

md_dict : dict
Flat dictionary with key-value pairs. Keys may contain section names. Values are strings, other types or dictionaries.
def set_metadata(metadata, mds, sep='.')

Set values of existing metadata.

Only if a key is found in the metadata, its value is updated.

Parameters

metadata : nested dict
Metadata.
mds : dict or str or list of str
  • Flat dictionary with key-value pairs for updating the metadata. Values can be strings, other types or dictionaries.
  • String with key and value separated by '='.
  • List of strings with key and value separated by '='. Keys may contain section names separated by sep.
sep : str
String that separates section names in the keys of md_dict.

Examples

>>> from audioio import print_metadata, set_metadata
>>> md = dict(Recording=dict(Time='early'))
>>> print_metadata(md)
Recording:
    Time: early

>>> set_metadata(md, {'Artist': 'John Doe',       # new key-value pair
                      'Recording.Time': 'late'})  # change value of existing key
>>> print_metadata(md)
Recording:
    Time   : late

See Also

add_metadata() strlist_to_dict()

def add_metadata(metadata, mds, sep='.')

Add or modify key-value pairs.

If a key does not exist, it is added to the metadata.

Parameters

metadata : nested dict
Metadata.
mds : dict or str or list of str
  • Flat dictionary with key-value pairs for updating the metadata. Values can be strings, other types or dictionaries.
  • String with key and value separated by '='.
  • List of strings with key and value separated by '='. Keys may contain section names separated by sep.
sep : str
String that separates section names in the keys of md_list.

Examples

>>> from audioio import print_metadata, add_metadata
>>> md = dict(Recording=dict(Time='early'))
>>> print_metadata(md)
Recording:
    Time: early

>>> add_metadata(md, {'Artist': 'John Doe',               # new key-value pair
                      'Recording.Time': 'late',           # change value of existing key 
                      'Recording.Quality': 'amazing',     # new key-value pair in existing section
                      'Location.Country': 'Lummerland'])  # new key-value pair in new section
>>> print_metadata(md)
Recording:
    Time   : late
    Quality: amazing
Artist: John Doe
Location:
    Country: Lummerland

See Also

set_metadata() strlist_to_dict()

def move_metadata(src_md, dest_md, keys, new_key=None, sep='.')

Remove a key from metadata and add it to a dictionary.

Parameters

src_md : nested dict
Metadata from which a key is removed.
dest_md : dict
Dictionary to which the found key and its value are added.
keys : str or list of str
List of keys to be searched for in src_md. Move the first one found to dest_md. See the audiometadata.find_key() function for details.
new_key : None or str
If specified add the value of the found key as new_key to dest_md. Otherwise, use the search key.
sep : str
String that separates section names in keys.

Returns

moved : bool
True if key was found and moved to dictionary.

Examples

>>> from audioio import print_metadata, move_metadata
>>> md = dict(Artist='John Doe', Recording=dict(Gain='1.42mV'))
>>> move_metadata(md, md['Recording'], 'Artist', 'Experimentalist')
>>> print_metadata(md)
Recording:
    Gain           : 1.42mV
    Experimentalist: John Doe
def remove_metadata(metadata, key_list, sep='.')

Remove key-value pairs or sections from metadata.

Parameters

metadata : nested dict
Metadata.
key_list : str or list of str
List of keys to key-value pairs or sections to be removed from the metadata.
sep : str
String that separates section names in the keys of key_list.

Examples

>>> from audioio import print_metadata, remove_metadata
>>> md = dict(aaaa=2, bbbb=dict(ccc=3, ddd=4))
>>> remove_metadata(md, ('ccc',))
>>> print_metadata(md)
aaaa: 2
bbbb:
    ddd: 4
def cleanup_metadata(metadata)

Remove empty sections from metadata.

Parameters

metadata : nested dict
Metadata.

Examples

>>> from audioio import print_metadata, cleanup_metadata
>>> md = dict(aaaa=2, bbbb=dict())
>>> cleanup_metadata(md)
>>> print_metadata(md)
aaaa: 2
def get_gain(metadata, gain_key=['gain'], sep='.', default=None, default_unit='', remove=False)

Get gain and unit from metadata.

Parameters

metadata : nested dict
Metadata with key-value pairs.
gain_key : str or list of str
Key in the file's metadata that holds some gain information. If found, the data will be multiplied with the gain, and if available, the corresponding unit is returned. See the audiometadata.find_key() function for details. You can modify the default keys via the default_gain_keys list of the audiometadata module.
sep : str
String that separates section names in gain_key.
default : None or float
Returned value if no valid gain was found in metadata.
default_unit : str
Returned unit if no valid gain was found in metadata.
remove : bool
If True, remove the found key from metadata.

Returns

fac : float
Gain factor. If not found in metadata return 1.
unit : string
Unit of the data if found in the metadata, otherwise "a.u.".
def update_gain(metadata, fac, gain_key=['gain'], sep='.')

Update gain setting in metadata.

Searches for the first appearance of a gain key in the metadata hierarchy. If found, divide the gain value by fac.

Parameters

metadata : nested dict
Metadata to be updated.
fac : float
Factor that was used to scale the data.
gain_key : str or list of str
Key in the file's metadata that holds some gain information. If found, the data will be multiplied with the gain, and if available, the corresponding unit is returned. See the audiometadata.find_key() function for details. You can modify the default keys via the default_gain_keys list of the audiometadata module.
sep : str
String that separates section names in gain_key.

Returns

done : bool
True if gain has been found and set.

Examples

>>> from audioio import print_metadata, update_gain
>>> md = dict(Artist='John Doe', Recording=dict(gain='1.4mV'))
>>> update_gain(md, 2)
>>> print_metadata(md)
Artist: John Doe
Recording:
    gain: 0.70mV
def update_starttime(metadata, deltat, rate, time_keys=[['DateTimeOriginal'], ['OriginationDate', 'OriginationTime'], ['Location_Time'], ['Timestamp']], ref_keys=['TimeReference'])

Update start-of-recording times in metadata.

Add deltat to time_keysand ref_keys fields in the metadata.

Parameters

metadata : nested dict
Metadata to be updated.
deltat : float
Time in seconds to be added to start times.
rate : float
Sampling rate of the data in Hertz.
time_keys : tuple of str or list of tuple of str
Keys to fields denoting calender times, i.e. dates and times. Datetimes can be stored in metadata as two separate key-value pairs, one for the date and one for the time. Or by a single key-value pair for a date-time values. This is why the keys need to be specified in tuples with one or two keys. Keys may contain section names separated by sep. See audiometadata.find_key() for details. You can modify the default time keys via the default_starttime_keys list of the audiometadata module.
ref_keys : str or list of str
Keys to time references, i.e. integers in seconds relative to a reference time. Keys may contain section names separated by sep. See audiometadata.find_key() for details. You can modify the default reference keys via the default_timeref_keys list of the audiometadata module.

Returns

success : bool
True if at least one time has been updated.

Example

>>> from audioio import print_metadata, update_starttime
>>> md = dict(DateTimeOriginal='2023-04-15T22:10:00',
              OtherTime='2023-05-16T23:20:10',
              BEXT=dict(OriginationDate='2024-03-02',
                        OriginationTime='10:42:24',
                        TimeReference=123456))
>>> update_starttime(md, 4.2, 48000)
>>> print_metadata(md)
DateTimeOriginal: 2023-04-15T22:10:04
OtherTime       : 2023-05-16T23:20:10
BEXT:
    OriginationDate: 2024-03-02
    OriginationTime: 10:42:28
    TimeReference  : 325056
def bext_history_str(encoding, rate, channels, text=None)

Assemble a string for the BEXT CodingHistory field.

Parameters

encoding : str or None
Encoding of the data.
rate : int or float
Sampling rate in Hertz.
channels : int
Number of channels.
text : str or None
Optional free text.

Returns

s : str
String for the BEXT CodingHistory field, something like "A=PCM_16,F=44100,W=16,M=stereo,T=cut out"
def add_history(metadata, history, new_key=None, pre_history=None, history_keys=['History', 'CodingHistory', 'BWF_CODING_HISTORY'], sep='.')

Add a string describing coding history to metadata.

Add history to the history_keys fields in the metadata. If none of these fields are present but new_key is specified, then assign pre_history and history to this key. If this key does not exist in the metadata, it is created.

Parameters

metadata : nested dict
Metadata to be updated.
history : str
String to be added to the history.
new_key : str or None
Sections and name of a history key to be added to metadata. Section names are separated by sep.
pre_history : str or None
If a new key new_key is created, then assign this string followed by history.
history_keys : str or list of str
Keys to fields where to add history. Keys may contain section names separated by sep. See audiometadata.find_key() for details. You can modify the default history keys via the default_history_keys list of the audiometadata module.
sep : str
String that separates section names in new_key and history_keys.

Returns

success : bool
True if the history string has beend added to the metadata.

Example

Add string to existing history key-value pair:

>>> from audioio import add_history
>>> md = dict(aaa='xyz', BEXT=dict(CodingHistory='original recordings'))
>>> add_history(md, 'just a snippet')
>>> print(md['BEXT']['CodingHistory'])
original recordings
just a snippet

Assign string to new key-value pair:

>>> md = dict(aaa='xyz', BEXT=dict(OriginationDate='2024-02-12'))
>>> add_history(md, 'just a snippet', 'BEXT.CodingHistory', 'original data')
>>> print(md['BEXT']['CodingHistory'])
original data
just a snippet
def add_unwrap(metadata, thresh, clip=0, unit='')

Add unwrap infos to metadata.

If audiotools.unwrap() was applied to the data, then this function adds relevant infos to the metadata. If there is an INFO section in the metadata, the unwrap infos are added to this section, otherwise they are added to the top level of the metadata hierarchy.

The threshold thresh used for unwrapping is saved under the key 'UnwrapThreshold' as a string. If clip is larger than zero, then the clip level is saved under the key 'UnwrapClippedAmplitude' as a string.

Parameters

md : nested dict
Metadata to be updated.
thresh : float
Threshold used for unwrapping.
clip : float
Level at which unwrapped data have been clipped.
unit : str
Unit of thresh and clip.

Examples

>>> from audioio import print_metadata, add_unwrap
>>> md = dict(INFO=dict(Time='early'))
>>> add_unwrap(md, 0.6, 1.0)
>>> print_metadata(md)
INFO:
    Time                  : early
    UnwrapThreshold       : 0.60
    UnwrapClippedAmplitude: 1.00
def demo(file_pathes, list_format, list_metadata, list_cues, list_chunks)

Print metadata and markers of audio files.

Parameters

file_pathes : list of str
Pathes of audio files.
list_format : bool
If True, list file format only.
list_metadata : bool
If True, list metadata only.
list_cues : bool
If True, list markers/cues only.
list_chunks : bool
If True, list all chunks contained in a riff/wave file.
def main(*cargs)

Call demo with command line arguments.

Parameters

cargs : list of strings
Command line arguments as provided by sys.argv[1:]