FPGA-RISC-V-CPU / hardware / scripts / audio / models / synth.py
synth.py
Raw
from dataclasses import dataclass, field
from typing import List

from FixedPoint import FXnum

from models.nco import NCO


@dataclass
class Synth:
    carrier_ncos: List[NCO]
    modulator_ncos: List[NCO]
    modulator_idx_shift: int = field(default=0)
    modulator_fcw: int = field(default=0)
    fcws: List[int] = field(init=False)
    note_enabled: List[bool] = field(init=False)
    # TODO: implement mixer

    def __post_init__(self):
        assert len(self.carrier_ncos) == len(self.modulator_ncos)
        assert all(self.carrier_ncos[0].fsamp == x.fsamp for x in self.carrier_ncos)
        assert all(self.modulator_ncos[0].fsamp == x.fsamp for x in self.modulator_ncos)
        self.fcws = [0] * len(self.carrier_ncos)
        self.note_enabled = [False] * len(self.carrier_ncos)

    def next_sample(self) -> FXnum:
        modulator_samples = [nco.next_sample(self.modulator_fcw if en else None)[0] for nco, en in zip(self.modulator_ncos, self.note_enabled)]
        # print("Mod Sample:", modulator_samples[0].scaledval)
        freq_modulated_fcws = [fcw + (mod_samp.scaledval << self.modulator_idx_shift) for fcw, mod_samp in zip(self.fcws, modulator_samples)]
        # print("Modulated FCWs:", freq_modulated_fcws)
        carrier_samples = [nco.next_sample(fcw if en else None)[0] for nco, fcw, en in zip(self.carrier_ncos, freq_modulated_fcws, self.note_enabled)]
        # print("Carrier Sample:", carrier_samples[0].scaledval)
        return sum(carrier_samples)