mirror of
https://github.com/iluvcapra/wavinfo.git
synced 2026-01-02 09:50:41 +00:00
Documentation
This commit is contained in:
94
docs/source/command_line.rst
Normal file
94
docs/source/command_line.rst
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
Using `wavinfo` from the Command Line
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
`wavinfo` installs a command-line entry point that will read wav files
|
||||||
|
from the command line and output metadata to stdout.
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$ wavinfo [--ixml | --adm] INFILE +
|
||||||
|
|
||||||
|
By default, `wavinfo` will output a JSON dictionary for each file argument.
|
||||||
|
|
||||||
|
|
||||||
|
Options
|
||||||
|
-------
|
||||||
|
|
||||||
|
Two option flags will change the behavior of the command:
|
||||||
|
|
||||||
|
``--ixml``
|
||||||
|
The *\-\-ixml* flag will cause `wavinfo` to output the iXML metadata payload
|
||||||
|
of each input wave file, or will emit an error message to stderr if iXML
|
||||||
|
metadata is not present.
|
||||||
|
|
||||||
|
``--adm``
|
||||||
|
The *\-\-adm* flag will cause `wavinfo` to output the ADM XML metadata
|
||||||
|
payload of each input wave file, or will emit an error message to stderr if
|
||||||
|
ADM XML metadata is not present.
|
||||||
|
|
||||||
|
These options are mutually-exclusive, with `\-\-adm` taking precedence.
|
||||||
|
|
||||||
|
|
||||||
|
Example Output
|
||||||
|
--------------
|
||||||
|
|
||||||
|
.. code-block:: javascript
|
||||||
|
|
||||||
|
{
|
||||||
|
"filename": "tests/test_files/sounddevices/A101_1.WAV",
|
||||||
|
"run_date": "2022-11-26T17:56:38.342935",
|
||||||
|
"application": "wavinfo 2.1.0",
|
||||||
|
"scopes": {
|
||||||
|
"fmt": {
|
||||||
|
"audio_format": 1,
|
||||||
|
"channel_count": 2,
|
||||||
|
"sample_rate": 48000,
|
||||||
|
"byte_rate": 288000,
|
||||||
|
"block_align": 6,
|
||||||
|
"bits_per_sample": 24
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"byte_count": 1441434,
|
||||||
|
"frame_count": 240239
|
||||||
|
},
|
||||||
|
"ixml": {
|
||||||
|
"track_list": [
|
||||||
|
{
|
||||||
|
"channel_index": "1",
|
||||||
|
"interleave_index": "1",
|
||||||
|
"name": "MKH516 A",
|
||||||
|
"function": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"channel_index": "2",
|
||||||
|
"interleave_index": "2",
|
||||||
|
"name": "Boom",
|
||||||
|
"function": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"project": "BMH",
|
||||||
|
"scene": "A101",
|
||||||
|
"take": "1",
|
||||||
|
"tape": "18Y12M31",
|
||||||
|
"family_uid": "USSDVGR1112089007124001008206300",
|
||||||
|
"family_name": null
|
||||||
|
},
|
||||||
|
"bext": {
|
||||||
|
"description": "sSPEED=023.976-ND\r\nsTAKE=1\r\nsUBITS=$12311801\r\nsSWVER=2.67\r\nsPROJECT=BMH\r\nsSCENE=A101\r\nsFILENAME=A101_1.WAV\r\nsTAPE=18Y12M31\r\nsTRK1=MKH516 A\r\nsTRK2=Boom\r\nsNOTE=\r\n",
|
||||||
|
"originator": "Sound Dev: 702T S#GR1112089007",
|
||||||
|
"originator_ref": "USSDVGR1112089007124001008206301",
|
||||||
|
"originator_date": "2018-12-31",
|
||||||
|
"originator_time": "12:40:00",
|
||||||
|
"time_reference": 2190940753,
|
||||||
|
"version": 1,
|
||||||
|
"umid": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"coding_history": "A=PCM,F=48000,W=24,M=stereo,R=48000,T=2 Ch\r\n",
|
||||||
|
"loudness_value": null,
|
||||||
|
"loudness_range": null,
|
||||||
|
"max_true_peak": null,
|
||||||
|
"max_momentary_loudness": null,
|
||||||
|
"max_shortterm_loudness": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -13,14 +13,12 @@ music production metadata.
|
|||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
:caption: Notes
|
:glob:
|
||||||
|
:numbered:
|
||||||
|
|
||||||
quickstart
|
quickstart
|
||||||
scopes/bext.rst
|
command_line
|
||||||
scopes/ixml.rst
|
scopes/*
|
||||||
scopes/adm.rst
|
|
||||||
scopes/dolby.rst
|
|
||||||
scopes/info.rst
|
|
||||||
|
|
||||||
classes
|
classes
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
wavinfo Quickstart
|
wavinfo Quickstart
|
||||||
====================
|
====================
|
||||||
|
|
||||||
|
All metadata is read by an instance of :class:`WaveInfoReader<wavinfo.wave_reader.WavInfoReader>`.
|
||||||
|
Each type of metadata, iXML, Broadcast-WAV etc. is accessible through *scopes*, properties on an
|
||||||
|
instance of :class:`WaveInfoReader`.
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
:caption: Using wavinfo
|
:caption: Using wavinfo
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ class TestWalk(unittest.TestCase):
|
|||||||
info = wavinfo.WavInfoReader(test_file)
|
info = wavinfo.WavInfoReader(test_file)
|
||||||
|
|
||||||
tested_data , tested_format = False, False
|
tested_data , tested_format = False, False
|
||||||
for scope, key, value in info.walk():
|
for scope, key, value in info.iter():
|
||||||
if scope == 'fmt':
|
if scope == 'fmt':
|
||||||
if key == 'channel_count':
|
if key == 'channel_count':
|
||||||
tested_format = True
|
tested_format = True
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from optparse import OptionParser, OptionGroup
|
from optparse import OptionParser, OptionGroup
|
||||||
import datetime
|
import datetime
|
||||||
from . import WavInfoReader
|
from . import WavInfoReader
|
||||||
|
from . import __version__
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
@@ -18,7 +19,7 @@ class MissingDataError(RuntimeError):
|
|||||||
def main():
|
def main():
|
||||||
parser = OptionParser()
|
parser = OptionParser()
|
||||||
|
|
||||||
parser.usage = 'wavinfo [FILES]'
|
parser.usage = 'wavinfo (--adm | --ixml) [FILES]'
|
||||||
|
|
||||||
# parser.add_option('-f', dest='output_format', help='Set the output format',
|
# parser.add_option('-f', dest='output_format', help='Set the output format',
|
||||||
# default='json',
|
# default='json',
|
||||||
@@ -38,15 +39,20 @@ def main():
|
|||||||
if this_file.adm:
|
if this_file.adm:
|
||||||
sys.stdout.write(this_file.adm.xml_str())
|
sys.stdout.write(this_file.adm.xml_str())
|
||||||
else:
|
else:
|
||||||
raise MissingDataError("--adm option active but ADM metadata not present")
|
raise MissingDataError("adm")
|
||||||
elif options.ixml:
|
elif options.ixml:
|
||||||
if this_file.ixml:
|
if this_file.ixml:
|
||||||
sys.stdout.write(this_file.ixml.xml_bytes())
|
sys.stdout.write(this_file.ixml.xml_bytes())
|
||||||
else:
|
else:
|
||||||
raise MissingDataError("--ixml option active but iXML metadata not present")
|
raise MissingDataError("ixml")
|
||||||
else:
|
else:
|
||||||
ret_dict = {'file_argument': arg, 'run_date': datetime.datetime.now().isoformat() , 'scopes': {}}
|
ret_dict = {
|
||||||
for scope, name, value in this_file.walk():
|
'filename': arg,
|
||||||
|
'run_date': datetime.datetime.now().isoformat() ,
|
||||||
|
'application': "wavinfo " + __version__,
|
||||||
|
'scopes': {}
|
||||||
|
}
|
||||||
|
for scope, name, value in this_file.iter():
|
||||||
if scope not in ret_dict['scopes'].keys():
|
if scope not in ret_dict['scopes'].keys():
|
||||||
ret_dict['scopes'][scope] = {}
|
ret_dict['scopes'][scope] = {}
|
||||||
|
|
||||||
@@ -54,8 +60,7 @@ def main():
|
|||||||
|
|
||||||
json.dump(ret_dict, cls=MyJSONEncoder, fp=sys.stdout, indent=2)
|
json.dump(ret_dict, cls=MyJSONEncoder, fp=sys.stdout, indent=2)
|
||||||
except MissingDataError as e:
|
except MissingDataError as e:
|
||||||
print("Missing metadata error in file %s" % arg, file=sys.stderr)
|
print("MissingDataError: Missing metadata (%s) in file %s" % (e, arg), file=sys.stderr)
|
||||||
print(e, file=sys.stderr)
|
|
||||||
continue
|
continue
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise e
|
raise e
|
||||||
|
|||||||
@@ -64,22 +64,25 @@ class WavInfoReader:
|
|||||||
|
|
||||||
self.path = absolute_path
|
self.path = absolute_path
|
||||||
|
|
||||||
#: Wave audio data format
|
#: Wave audio data format.
|
||||||
self.fmt :Optional[WavAudioFormat] = None
|
self.fmt :Optional[WavAudioFormat] = None
|
||||||
|
|
||||||
#: Broadcast-Wave metadata
|
#: Statistics of the `data` section.
|
||||||
|
self.data :Optional[WavDataDescriptor] = None
|
||||||
|
|
||||||
|
#: Broadcast-Wave metadata.
|
||||||
self.bext :Optional[WavBextReader] = None
|
self.bext :Optional[WavBextReader] = None
|
||||||
|
|
||||||
#: iXML metadata
|
#: iXML metadata.
|
||||||
self.ixml :Optional[WavIXMLFormat] = None
|
self.ixml :Optional[WavIXMLFormat] = None
|
||||||
|
|
||||||
#: ADM Audio Definiton Model metadata
|
#: ADM Audio Definiton Model metadata.
|
||||||
self.adm :Optional[WavADMReader]= None
|
self.adm :Optional[WavADMReader]= None
|
||||||
|
|
||||||
#: Dolby Bitstream Metadata
|
#: Dolby bitstream metadata.
|
||||||
self.dolby :Optional[WavDolbyMetadataReader] = None
|
self.dolby :Optional[WavDolbyMetadataReader] = None
|
||||||
|
|
||||||
#: RIFF INFO Metadata
|
#: RIFF INFO metadata.
|
||||||
self.info :Optional[WavInfoChunkReader]= None
|
self.info :Optional[WavInfoChunkReader]= None
|
||||||
|
|
||||||
with open(path, 'rb') as f:
|
with open(path, 'rb') as f:
|
||||||
@@ -163,7 +166,7 @@ class WavInfoReader:
|
|||||||
ixml_data = self._find_chunk_data(b'iXML', f, default_none=True)
|
ixml_data = self._find_chunk_data(b'iXML', f, default_none=True)
|
||||||
return WavIXMLFormat(ixml_data.rstrip(b'\0')) if ixml_data else None
|
return WavIXMLFormat(ixml_data.rstrip(b'\0')) if ixml_data else None
|
||||||
|
|
||||||
def walk(self) -> Generator[str,str,Any]:
|
def iter(self) -> Generator[str,str,Any]:
|
||||||
"""
|
"""
|
||||||
Walk all of the available metadata fields.
|
Walk all of the available metadata fields.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user