diff --git a/lib/pimoroni_yukon/devices/audio.py b/lib/pimoroni_yukon/devices/audio.py index c547c28..f47c5d4 100644 --- a/lib/pimoroni_yukon/devices/audio.py +++ b/lib/pimoroni_yukon/devices/audio.py @@ -1,11 +1,10 @@ -# SPDX-FileCopyrightText: 2023 Christopher Parrott for Pimoroni Ltd +# SPDX-FileCopyrightText: 2024 Christopher Parrott for Pimoroni Ltd # # SPDX-License-Identifier: MIT -import os import math import struct -from machine import I2S +from machine import I2S, Pin """ A class for playing Wav files out of an I2S audio amp. It can also play pure tones. @@ -14,6 +13,70 @@ """ +class WavReader: + def __init__(self, file): + self.wav_file = open(file, "rb") + self._parse(self.wav_file) + + def _parse(self, wav_file): + chunk_ID = wav_file.read(4) + if chunk_ID != b"RIFF": + raise ValueError("WAV chunk ID invalid") + _ = wav_file.read(4) # chunk_size + if wav_file.read(4) != b"WAVE": + raise ValueError("WAV format invalid") + sub_chunk1_ID = wav_file.read(4) + if sub_chunk1_ID != b"fmt ": + raise ValueError("WAV sub chunk 1 ID invalid") + _ = wav_file.read(4) # sub_chunk1_size + _ = struct.unpack("WAV converters add + # binary data before "data". So, read a fairly large + # block of bytes and search for "data". + + binary_block = wav_file.read(200) + offset = binary_block.find(b"data") + if offset == -1: + raise ValueError("WAV sub chunk 2 ID not found") + + self.offset = offset + 44 + + wav_file.seek(offset + 40) + self.size = struct.unpack(" 20_000: raise ValueError("frequency out of range. Expected between 20Hz and 20KHz") if amplitude < 0.0 or amplitude > 1.0: raise ValueError("amplitude out of range. Expected 0.0 to 1.0") + if not isinstance(shape, (list, tuple)): + shape = (shape, ) + # Create a buffer containing the pure tone samples samples_per_cycle = self.TONE_SAMPLE_RATE // frequency sample_size_in_bytes = self.TONE_BITS_PER_SAMPLE // 8 samples = bytearray(self.TONE_FULL_WAVES * samples_per_cycle * sample_size_in_bytes) - range = pow(2, self.TONE_BITS_PER_SAMPLE) // 2 + maximum = (pow(2, self.TONE_BITS_PER_SAMPLE) // 2 - 1) * amplitude format = "WAV converters add - # binary data before "data". So, read a fairly large - # block of bytes and search for "data". - - binary_block = wav_file.read(200) - offset = binary_block.find(b"data") - if offset == -1: - raise ValueError("WAV sub chunk 2 ID not found") - - return (format, sample_rate, bits_per_sample, 44 + offset)