diff --git a/examples/demo.ipynb b/examples/demo.ipynb index 7e6de5e..f478d1d 100644 --- a/examples/demo.ipynb +++ b/examples/demo.ipynb @@ -6,12 +6,21 @@ "source": [ "# `wavinfo` Demonstration\n", "\n", - "The entry point for wavinfo is the WavInfoReader class." + "The `wavinfo` module allows you to read most of the metadata formats that are available for WAV files." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Opening a WAV file for reading metadata\n", + "\n", + "The entry point for wavinfo is the `WavInfoReader` class:" ] }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -26,14 +35,32 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Basic WAV Data\n", + "Once you have a `WavInfoReader`, you can access different metadata systems or \"scopes.\"\n", + "\n", + "The scopes that are presently supported are: `fmt`, `data`, `ixml`, `bext`, `info`, `adm`, `cues`, and `dolby`. Each of these is an attribute of a `WavInfoReader` object.\n", + "\n", + "Each scope roughly corresponds to a vendor-defined metadata system. Many scopes directly represent a specific file *chunk*, like `fmt` or `ixml`, and some may involve data read from many chunks. Examples of this would include `cues` or `adm`.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Metadata Scopes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `data` and `fmt`: Basic WAV Data\n", "\n", "The length of the file in frames (interleaved samples) and bytes is available, as is the contents of the format chunk." ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -42,7 +69,7 @@ "(240239, 1441434)" ] }, - "execution_count": 2, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -51,9 +78,16 @@ "(info.data.frame_count, info.data.byte_count)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `fmt` scope allows the client to read metadata from the WAVE format description." + ] + }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -62,7 +96,7 @@ "(48000, 2, 6, 24)" ] }, - "execution_count": 3, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -75,29 +109,31 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Broadcast WAV Extension" + "### `bext`: Broadcast WAV Extension\n", + "\n", + "The `bext` scope allows the client to access Broadcast-WAV metadata. " ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "sSPEED=023.976-ND\r\n", - "sTAKE=1\r\n", - "sUBITS=$12311801\r\n", - "sSWVER=2.67\r\n", - "sPROJECT=BMH\r\n", - "sSCENE=A101\r\n", - "sFILENAME=A101_1.WAV\r\n", - "sTAPE=18Y12M31\r\n", - "sTRK1=MKH516 A\r\n", - "sTRK2=Boom\r\n", - "sNOTE=\r\n", + "sSPEED=023.976-ND\n", + "sTAKE=1\n", + "sUBITS=$12311801\n", + "sSWVER=2.67\n", + "sPROJECT=BMH\n", + "sSCENE=A101\n", + "sFILENAME=A101_1.WAV\n", + "sTAPE=18Y12M31\n", + "sTRK1=MKH516 A\n", + "sTRK2=Boom\n", + "sNOTE=\n", "\n", "----------\n", "Originator: Sound Dev: 702T S#GR1112089007\n", @@ -105,7 +141,7 @@ "Originator Date: 2018-12-31\n", "Originator Time: 12:40:00\n", "Time Reference: 2190940753\n", - "A=PCM,F=48000,W=24,M=stereo,R=48000,T=2 Ch\r\n", + "A=PCM,F=48000,W=24,M=stereo,R=48000,T=2 Ch\n", "\n" ] } @@ -125,12 +161,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## iXML Production Recorder Metadata" + "### `ixml`: iXML Production Recorder Metadata" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -155,12 +191,80 @@ "print(\"iXML File Family UID:\", info.ixml.family_uid)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `cues`: Cues Metadata\n", + "\n", + "Cue time markers are accessible through the `cues` scope. The `each_cue` method returns an iterator that yields a tuple of each cue \"name\" or integer UID, and sample location. " + ] + }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Cue ID: 1\n", + "Cue Offset: 29616\n", + "Cue ID: 2\n", + "Cue Offset: 74592\n", + "Cue ID: 3\n", + "Cue Offset: 121200\n" + ] + } + ], + "source": [ + "path = \"../tests/test_files/cue_chunks/STE-000.wav\"\n", + "info = WavInfoReader(path)\n", + "\n", + "for cue in info.cues.each_cue():\n", + " print(f\"Cue ID: {cue[0]}\")\n", + " print(f\"Cue Offset: {cue[1]}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are also convenience methods to get the appropriate label and note for a given marker. (Note here also `WavInfoReader`'s facility for overriding default text encodings.)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Cue ID: 1\n", + " Label: Marker 1\n", + " Note: \n", + "Cue ID: 2\n", + " Label: Marker 2\n", + " Note: Marker Comment 1\n", + "Cue ID: 3\n", + " Label: Marker 3\n", + " Note: Лорем ипсум долор сит амет, тимеам вивендум хас ет, цу адолесценс дефинитионес еам.\n" + ] + } + ], + "source": [ + "path = \"../tests/test_files/cue_chunks/izotoperx_cues_test.wav\"\n", + "info = WavInfoReader(path, info_encoding=\"utf-8\")\n", + "\n", + "for cue in info.cues.each_cue():\n", + " print(f\"Cue ID: {cue[0]}\")\n", + " label, note = info.cues.label_and_note(cue[0])\n", + " print(f\" Label: {label}\")\n", + " print(f\" Note: {note or ''}\")" + ] }, { "cell_type": "code", @@ -172,7 +276,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -186,9 +290,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.2" + "version": "3.11.5" } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/examples/wavinfo.ipynb b/examples/wavinfo.ipynb deleted file mode 100644 index ba3df78..0000000 --- a/examples/wavinfo.ipynb +++ /dev/null @@ -1,215 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import wavinfo\n", - "import pprint" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "pp = pprint.PrettyPrinter(indent=4)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "path = '../tests/test_files/protools/PT A101_4.A1.wav'\n", - "\n", - "info = wavinfo.WavInfoReader(path)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[ ChunkDescriptor(ident=b'bext', start=20, length=858),\n", - " ChunkDescriptor(ident=b'iXML', start=886, length=5226),\n", - " ChunkDescriptor(ident=b'fmt ', start=6120, length=16),\n", - " ChunkDescriptor(ident=b'data', start=6144, length=864840),\n", - " ChunkDescriptor(ident=b'umid', start=870992, length=24),\n", - " ChunkDescriptor(ident=b'minf', start=871024, length=16),\n", - " ChunkDescriptor(ident=b'regn', start=871048, length=92)]\n" - ] - } - ], - "source": [ - "import wavinfo.wave_parser\n", - "\n", - "with open(path,'rb') as f:\n", - " chunk_tree = wavinfo.wave_parser.parse_chunk(f)\n", - "\n", - "pp.pprint(chunk_tree.children)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00*\\xfd\\xf5\\x0c$\\xe4s\\x80\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n", - "000000000000002afdf50c24e47380000000000000000000\n", - "24\n" - ] - } - ], - "source": [ - "with open(path,'rb') as f:\n", - " f.seek( chunk_tree.children[4].start )\n", - " umid_bin = f.read(chunk_tree.children[4].length)\n", - " f.seek( chunk_tree.children[6].start )\n", - " regn_bin = f.read(chunk_tree.children[6].length)\n", - " \n", - "print(umid_bin)\n", - "print(umid_bin.hex())\n", - "print(len(umid_bin))" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - } - ], - "source": [ - "print(info.bext)" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00*\\xfd\\xf5\\x0c$\\xe4s\\x80\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x0c3\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00T\\xd5\\xa2\\x82\\x00\\x00\\x00\\x00\\x10PT A101_4.A1.wavGK\\xaa\\xaf\\x7f\\x00\\x00@ }\\x06\\x00`\\x00\\x00'\n", - "01000000000000000000002afdf50c24e473800000000000000000000c330200000000000000000000000000000000000000000054d5a2820000000010505420413130315f342e41312e776176474baaaf7f000040207d0600600000\n", - "92\n" - ] - } - ], - "source": [ - "\n", - "print(regn_bin)\n", - "print(regn_bin.hex())\n", - "print(len(regn_bin))" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{ 'artist': 'Frank Bry',\n", - " 'comment': 'BULLET Impact Plastic LCD TV Screen Shatter Debris 2x',\n", - " 'copyright': '2018 Creative Sound Design, LLC (The Recordist Christmas '\n", - " '2018) www.therecordist.com',\n", - " 'created_date': '2018-11-15',\n", - " 'engineer': None,\n", - " 'genre': 'Bullets',\n", - " 'keywords': None,\n", - " 'product': 'The Recordist Christmas 2018',\n", - " 'software': 'Soundminer',\n", - " 'source': None,\n", - " 'tape': None,\n", - " 'title': None}\n", - "{ 'coding_history': '',\n", - " 'description': 'BULLET Impact Plastic LCD TV Screen Shatter Debris 2x',\n", - " 'loudness_range': None,\n", - " 'loudness_value': None,\n", - " 'max_momentary_loudness': None,\n", - " 'max_shortterm_loudness': None,\n", - " 'max_true_peak': None,\n", - " 'originator': 'TheRecordist',\n", - " 'originator_date': '2018-12-20',\n", - " 'originator_ref': 'aaiAKt3fCGTk',\n", - " 'originator_time': '12:15:37',\n", - " 'time_reference': 57882,\n", - " 'version': 0}\n" - ] - } - ], - "source": [ - "path = '../tests/test_files/BULLET Impact Plastic LCD TV Screen Shatter Debris 2x.wav'\n", - "\n", - "info = wavinfo.WavInfoReader(path)\n", - "\n", - "with open(path,'rb') as f:\n", - " chunk_tree = wavinfo.wave_parser.parse_chunk(f)\n", - " \n", - "pp.pprint(info.info.to_dict())\n", - "pp.pprint(info.bext.to_dict())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -}