Exercise 2 solution import struct def make_wav(pcm, rate=8000, channels=1, tag=1, byte_rate=None): if byte_rate is None: byte_rate = rate * channels * 2 fmt = struct.pack(" len(raw): raise ValueError(f"chunk {cid!r} runs past end of file") chunks[cid] = raw[pos + 8:pos + 8 + size] pos += 8 + size + (size & 1) if b"fmt " not in chunks or b"data" not in chunks: raise ValueError("missing fmt or data chunk") tag, ch, rate, brate, align, bits = struct.unpack_from("", e) # {'channels': 1, 'rate': 8000, 'bits': 16, 'frames': 8000, 'seconds': 1.0} # {'channels': 2, 'rate': 44100, 'bits': 16, 'frames': 44100, 'seconds': 1.0} # tag 3 -> format tag 3 is not plain PCM # byte rate -> byte rate or block align does not match the other fields (Run as written; the output matched the comments.) Explanation: A frame is one sample for every channel, so its size is the block align, channels times bytes per sample. Frames divided by the sample rate gives the duration. The describe function refuses any format tag other than 1 (plain PCM) and any file whose redundant fields (byte rate and block align) disagree with the rest, because a file that contradicts itself cannot be trusted.