Index: mosAudioDataBody.py
===================================================================
--- AmmosAudioDataBody.py	(revision 44aebd3ef3207c4da09f0b7f6a70c2c27d5bc8ea)
+++ 	(revision )
@@ -1,1 +1,0 @@
-#!/usr/bin/env python3
Index: AmmosAudioReader.py
===================================================================
--- AmmosAudioReader.py	(revision 44aebd3ef3207c4da09f0b7f6a70c2c27d5bc8ea)
+++ AmmosAudioReader.py	(revision 6cb85c27f904f32e3ec427f40f7bb081a23c6b30)
@@ -1,3 +1,4 @@
-import math
+"""I parse an R&S AMMOS recording."""
+
 import os
 
@@ -11,7 +12,17 @@
 
 class AmmosAudioReader():
+    """I read the audio data embedded in an R&S AMMOS recording."""
+
+    GLOBAL_HEADER_SIZE = 24  # 8 words
+    STANDARD_AUDIO_DATA_HEADER_SIZE = 36  # 9 words
+    EXTENDED_AUDIO_DATA_HEADER_SIZE = 44  # 11 words
 
     def __init__(self, file_name):
-
+        """
+        I return an instance of AmmosAudioReader initialized with a given file name.
+
+        :param file_name: the file to read from
+        :type file_name: str
+        """
         self.file_name = file_name
         self.file = open(self.file_name, "rb")
@@ -20,16 +31,27 @@
         self.container = AmmosContainer(self.file_name, [])
 
-        self.tags = []
+        self.tags = {}
 
     def rewind_to_start(self):
+        """I set the file pointer to the beginning of the file for the next operation."""
         self.file.seek(0)
 
     def add_tag(self, tag):
-        self.tags.append(tag)
+        """
+        I add a tag to my tag list.
+
+        :param tag: The tag to add to my tag list
+        :type tag: dict
+        """
+        self.tags[tag.key] = tag.value
 
     def read_all_frames_left(self):
-
+        """
+        I read all remaining frames into my container until end of file is reached.
+
+        :return: a container containing all frames read
+        :rtype: AmmosContainer
+        """
         frames_read = 0
-
         while True:
             print("Reading single frame", frames_read, '...')
@@ -45,43 +67,73 @@
 
         print(len(self.container.global_frames), "frames read")
+        return self.container
 
     def read_next_global_frame_header(self):
-        bytes = self.file.read(24)
+        """
+        I return the next global frame header read from current position in file.
+
+        :return: the next global frame header or None if incomplete
+        :rtype: AmmosGlobalFrameHeader
+        """
+        bytes = self.file.read(AmmosAudioReader.GLOBAL_HEADER_SIZE)
         print("Reading next global frame header")
-        if ((not bytes) or (len(bytes) < 24)):
-            print("Can not read all 24 bytes of global frame header")
-            return None
-
+        if ((not bytes) or (len(bytes) < AmmosAudioReader.GLOBAL_HEADER_SIZE)):
+            print("Can not read all", AmmosAudioReader.GLOBAL_HEADER_SIZE, "bytes of global frame header")
+            return None
+
+        # FIXME: Catch exceptions and add some asserts
         current_global_frame_header = AmmosGlobalFrameHeader.from_bytes(bytes)
-        print("Current global frame header", current_global_frame_header)
+        # print("Current global frame header", current_global_frame_header)
         return current_global_frame_header
 
     def read_next_global_frame_body_data_header(self):
-
-        bytes = self.file.read(56)
+        """
+        I return the next global frame body data header from current position in file.
+
+        :param data_header_size: the number of bytes to read
+        :type data_header_size: int
+        :return: the next Ammos Audio Data header or None if incomplete
+        :rtype: AmmosAudioDataHeader
+        """
+        bytes = self.file.read(AmmosAudioReader.STANDARD_AUDIO_DATA_HEADER_SIZE)
 
         # print("\nReading global frame body standard data header\n")
-        if ((not bytes) or (len(bytes) < 56)):
-            print("Can not read all 56 bytes of global frame body data header")
-            return None
-
-        data_header = AmmosAudioDataHeader.from_bytes(bytes)
-        # print("Data header", data_header)
-        return data_header
+        if ((not bytes) or (len(bytes) < AmmosAudioReader.STANDARD_AUDIO_DATA_HEADER_SIZE)):
+            print("Can not read all", AmmosAudioReader.STANDARD_AUDIO_DATA_HEADER_SIZE,
+                  "bytes of global frame body data header")
+            return None
+        return AmmosAudioDataHeader.from_bytes(bytes)
 
     def read_next_global_frame_body_extended_data_header(self):
-
-        bytes = self.file.read(44)
-        # print("\nReading global frame body extended data header\n")
-
-        if ((not bytes) or (len(bytes) < 44)):
-            print("Can not read all ", 44, "bytes of global frame extended data header")
-            return None
-        extended_data_header = AmmosExtendedAudioDataHeader.from_bytes(bytes)
-        # print("Extended data header", extended_data_header)
-        return extended_data_header
+        """
+        I return the next global frame body extended data header from current position in file.
+
+        :return: the next Ammos Audio Extended Data header or None if incomplete
+        :rtype: AmmosExtendedAudioDataHeader
+        """
+        bytes = self.file.read(AmmosAudioReader.EXTENDED_AUDIO_DATA_HEADER_SIZE)
+
+        if ((not bytes) or (len(bytes) < AmmosAudioReader.EXTENDED_AUDIO_DATA_HEADER_SIZE)):
+            print("Can not read all ", AmmosAudioReader.EXTENDED_AUDIO_DATA_HEADER_SIZE,
+                  " bytes of global frame extended data header")
+            return None
+        return AmmosExtendedAudioDataHeader.from_bytes(bytes)
 
     def read_next_audio_data_body(self, sample_count, channel_count, sample_size):
-
+        """
+        I return the next audio data read from current position in file.
+
+        :param sample_count: the number of samples per channel inside data body
+        :type sample_count: int
+
+        :param channel_count: number of channels (e.g. mono, stereo or even more)
+        :type channel_count: int
+
+        :param sample_size: sample size in bytes (1, 2 or 4 bytes)
+        :type sample_size: int
+
+        :return: the next audio data or None if incomplete
+        :rtype: bytes
+        """
         # FIXME: Describe the parameters better
 
@@ -100,14 +152,14 @@
         audio_data_header = None
 
-        if global_frame_header.data_header_length == 36:
+        if global_frame_header.data_header_length == AmmosAudioReader.STANDARD_AUDIO_DATA_HEADER_SIZE:
             print("Read standard data header")
             audio_data_header = self.read_next_global_frame_body_data_header()
 
-        else:
+        if global_frame_header.data_header_length == AmmosAudioReader.EXTENDED_AUDIO_DATA_HEADER_SIZE:
             print("Read extended data header")
             audio_data_header = self.read_next_global_frame_body_extended_data_header()
 
         if audio_data_header is None:
-            print("Data header missing")
+            print("Data header missing or format unknown")
             return None
 
@@ -125,4 +177,6 @@
 
         global_frame_header = self.read_next_global_frame_header()
+
+        print(global_frame_header)
 
         if global_frame_header is None:
Index: org/audio.html
===================================================================
--- org/audio.html	(revision 6cb85c27f904f32e3ec427f40f7bb081a23c6b30)
+++ org/audio.html	(revision 6cb85c27f904f32e3ec427f40f7bb081a23c6b30)
@@ -0,0 +1,183 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="utf-8"/>
+<title>Audio</title>
+<meta name="author" content="Enrico Schwass"/>
+<style type="text/css">
+.underline { text-decoration: underline; }
+</style>
+<link rel="stylesheet" href="/home/enno/.emacs.d/.local/straight/build-28.0.50/revealjs/dist/reveal.css"/>
+
+<link rel="stylesheet" href="/home/enno/.emacs.d/.local/straight/build-28.0.50/revealjs/dist/theme/black.css" id="theme"/>
+</head>
+<body>
+<div class="reveal">
+<div class="slides">
+<section id="sec-title-slide">
+<h1 class="title">Audio</h1><h2 class="author">Enrico Schwass</h2><p class="date">Created: 2022-05-03 Tue 13:09</p>
+</section>
+<section id="table-of-contents-section">
+<div id="table-of-contents" role="doc-toc">
+<h2>Table of Contents</h2>
+<div id="text-table-of-contents" role="doc-toc">
+<ul>
+<li><a href="#/slide-1">1. Description Audio sample file AudioAufzeichnungLOW.bin</a>
+<ul>
+<li><a href="#/slide-1-1">1.1. Global Frame Header (6 x 32 Bit) Offset 0x00000000</a>
+<ul>
+<li><a href="#/slide-1-1-1">1.1.1. 32 Bit Magic word 0x726574fb = 0xfb746572 next magic bytes found at offsets</a></li>
+<li><a href="#/slide-1-1-2">1.1.2. 32 Bit Frame length in 32 bit words</a></li>
+<li><a href="#/slide-1-1-3">1.1.3. 32 Bit Running Frame number</a></li>
+<li><a href="#/slide-1-1-4">1.1.4. 32 Bit Frame Type</a></li>
+<li><a href="#/slide-1-1-5">1.1.5. 32 Bit Data header length in 32 bit words</a></li>
+<li><a href="#/slide-1-1-6">1.1.6. 32 Bit Reserved</a></li>
+</ul>
+</li>
+<li><a href="#/slide-1-2">1.2. Ammos Data header 44 bytes</a></li>
+<li><a href="#/slide-1-3">1.3. Ammos Audio Data Body</a></li>
+</ul>
+</li>
+</ul>
+</div>
+</div>
+</section>
+
+<section>
+<section id="slide-1">
+<h2 id="1"><span class="section-number-2">1.</span> Description Audio sample file AudioAufzeichnungLOW.bin</h2>
+<p>
+Little Endian!!!
+</p>
+
+</section>
+<section id="slide-1-1">
+<h3 id="1-1"><span class="section-number-3">1.1.</span> Global Frame Header (6 x 32 Bit) Offset 0x00000000</h3>
+<div class="outline-text-3" id="text-1-1">
+</div>
+</section>
+<section id="slide-1-1-1">
+<h4 id="1-1-1"><span class="section-number-4">1.1.1.</span> 32 Bit Magic word 0x726574fb = 0xfb746572 next magic bytes found at offsets</h4>
+<p>
+0x0000 (0000)
+0x0544 (1348)
+0x0a88 (2696)
+0x0fcf (4047)
+0x1510 (5392)
+0x1a57 (6743)
+0x1f9b (8091)
+0x24df (9439)
+</p>
+
+</section>
+<section id="slide-1-1-2">
+<h4 id="1-1-2"><span class="section-number-4">1.1.2.</span> 32 Bit Frame length in 32 bit words</h4>
+<p>
+0x51010000 = 0x00000151 = Integer 337 * 4 bytes = 1348 Bytes = 0x0544
+</p>
+
+</section>
+<section id="slide-1-1-3">
+<h4 id="1-1-3"><span class="section-number-4">1.1.3.</span> 32 Bit Running Frame number</h4>
+<p>
+0x23450000 = 0x00004523 = Integer 17699
+</p>
+
+</section>
+<section id="slide-1-1-4">
+<h4 id="1-1-4"><span class="section-number-4">1.1.4.</span> 32 Bit Frame Type</h4>
+<p>
+0x00010000 = 0x00000100 = Integer 256
+</p>
+
+</section>
+<section id="slide-1-1-5">
+<h4 id="1-1-5"><span class="section-number-4">1.1.5.</span> 32 Bit Data header length in 32 bit words</h4>
+<p>
+0x0b000000 = 0x0000000b = Integer 11 * 4 = 44 Bytes
+</p>
+
+</section>
+<section id="slide-1-1-6">
+<h4 id="1-1-6"><span class="section-number-4">1.1.6.</span> 32 Bit Reserved</h4>
+<p>
+0x00000000 = 0x00000000 = Integer 0
+</p>
+
+</section>
+<section id="slide-1-2">
+<h3 id="1-2"><span class="section-number-3">1.2.</span> Ammos Data header 44 bytes</h3>
+<p>
+4 Bytes Sample rate
+4 Bytes Status
+8 Bytes Frequency
+4 Bytes Demod Bandwidth
+4 Bytes Demod Type
+4 Bytes Sample Count
+4 Bytes Channel Count
+4 Bytes Sample Size
+</p>
+
+<p>
+8 Bytes timestamp if extended
+</p>
+
+<p>
+0xd4300000 = 0x000030d4 = 12500 Sample rate
+0x00000000 = 0x00000000 = 0 Squelch Status
+0xc0d3f205 0x00000000 = 0x00000000 0x05f2d3c0 = 99800000 = 99.8 MHz
+0xc0d40100 = 0x0001d4c0 = 120000 = 120 KHz
+0x00000000 = 0x00000000 = 0 = FM
+0x80020000 = 0x00000280 = Integer 640 = Sample Count per Channel
+0x01000000 = 0x00000001 = 1 = 1 Channel
+0x02000000 = 0x00000002 = 2 = 2 Bytes Sample size
+0x1d26fe89 0xcada0500 = 0x0005daca 0x89fe261d = 1647938316938525 microseconds Unixtime = 2022-03-22T09:38:36
+</p>
+
+</section>
+<section id="slide-1-3">
+<h3 id="1-3"><span class="section-number-3">1.3.</span> Ammos Audio Data Body</h3>
+<p>
+Offset 0x0044 = Integer 68 - Next offset 1348 - Differenz = 1280
+</p>
+</section>
+</section>
+</div>
+</div>
+<script src="/home/enno/.emacs.d/.local/straight/build-28.0.50/revealjs/dist/reveal.js"></script>
+<script src="/home/enno/.emacs.d/.local/straight/build-28.0.50/revealjs/plugin/markdown/markdown.js"></script>
+<script src="/home/enno/.emacs.d/.local/straight/build-28.0.50/revealjs/plugin/notes/notes.js"></script>
+<script src="/home/enno/.emacs.d/.local/straight/build-28.0.50/revealjs/plugin/search/search.js"></script>
+<script src="/home/enno/.emacs.d/.local/straight/build-28.0.50/revealjs/plugin/zoom/zoom.js"></script>
+<script>
+// Full list of configuration options available here:
+// https://github.com/hakimel/reveal.js#configuration
+Reveal.initialize({
+
+controls: true,
+progress: true,
+history: false,
+center: true,
+slideNumber: 'c',
+rollingLinks: false,
+keyboard: true,
+mouseWheel: false,
+fragmentInURL: false,
+hashOneBasedIndex: false,
+pdfSeparateFragments: true,
+overview: true,
+
+transition: 'convex',
+transitionSpeed: 'default',
+
+// Plugins with reveal.js 4.x
+plugins: [ RevealMarkdown, RevealNotes, RevealSearch, RevealZoom ],
+
+// Optional libraries used to extend reveal.js
+dependencies: [
+]
+
+});
+</script>
+</body>
+</html>
