# Copyright © 2026 Remco van 't Veer
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.

import machine

class Sound:
    i2s_id = 0
    bits = 16
    format = machine.I2S.MONO
    rate = 8000
    ibuf = 1000

    def __init__(self, *,
                 sck_gpio = None,
                 ws_gpio = None,
                 sd_gpio = None):
        self.sck_pin = machine.Pin(sck_gpio)
        self.ws_pin = machine.Pin(ws_gpio)
        self.sd_pin = machine.Pin(sd_gpio)
        self.samples = bytearray(1000)
        self.samples_mv = memoryview(self.samples)
        self.silence = bytearray(1000)

        self.i2s = self.wav = None
        self.stopped = True
        self.flush = 0

    def stop(self):
        if self.i2s:
            self.stopped = True
            self.flush = 2

        if self.wav:
            self.wav.close()
            self.wav = None

    def play(self, file):
        self.stop()

        self.stopped = False

        self.wav = open(file, "rb")
        self.wav.seek(44)

        self.i2s = machine.I2S(self.i2s_id,
                               sck = self.sck_pin,
                               ws = self.ws_pin,
                               sd = self.sd_pin,
                               mode = machine.I2S.TX,
                               bits = self.bits,
                               format = self.format,
                               rate = self.rate,
                               ibuf = self.ibuf)
        self.i2s.irq(self.__callback)
        self.i2s.write(self.silence)

    def __callback(self, _):
        if self.stopped:
            self.i2s.write(self.silence)

            self.flush -= 1
            if self.flush > 0:
                self.i2s.write(self.silence)
            else:
                self.i2s.deinit()
                self.i2s = None
        else:
            n = self.wav.readinto(self.samples_mv)
            if n == 0:
                self.wav.seek(44)
                self.i2s.write(self.silence)
            else:
                self.i2s.write(self.samples_mv[:n])

    def is_playing(self):
        return self.i2s is not None

if __name__ == "__main__":
    import time
    sound = Sound(sck_gpio = 1,
                  ws_gpio = 2,
                  sd_gpio = 0)
    sound.play("rooster.wav")
    time.sleep(5)
    sound.stop()
