add nihav_qt crate with some QuickTime codecs
[nihav.git] / nihav-qt / src / codecs / qdm2fft.rs
diff --git a/nihav-qt/src/codecs/qdm2fft.rs b/nihav-qt/src/codecs/qdm2fft.rs
new file mode 100644 (file)
index 0000000..22ca5dc
--- /dev/null
@@ -0,0 +1,596 @@
+use nihav_core::codecs::*;
+use nihav_core::io::codebook::*;
+use nihav_codec_support::dsp::fft::*;
+use super::qdmcommon::*;
+use super::qdm2::TONE_SCALES;
+use std::f32::consts::PI;
+
+struct Codebooks {
+    group_cb:           [Codebook<u8>; 5],
+    level_exp_alt_cb:   Codebook<u8>,
+    level_exp_cb:       Codebook<u8>,
+    stereo_exp_cb:      Codebook<u8>,
+    phase_diff_cb:      Codebook<u8>,
+}
+
+fn map_idx(idx: usize) -> u8 { idx as u8 }
+
+macro_rules! create_codebook {
+    ($codes: expr, $bits: expr) => ({
+        let mut cbr = TableCodebookDescReader::new($codes, $bits, map_idx);
+        Codebook::new(&mut cbr, CodebookMode::LSB).unwrap()
+    })
+}
+
+impl Codebooks {
+    fn new() -> Self {
+        let cb0 = create_codebook!(FFT_GROUP_CODES[0], FFT_GROUP_BITS[0]);
+        let cb1 = create_codebook!(FFT_GROUP_CODES[1], FFT_GROUP_BITS[1]);
+        let cb2 = create_codebook!(FFT_GROUP_CODES[2], FFT_GROUP_BITS[2]);
+        let cb3 = create_codebook!(FFT_GROUP_CODES[3], FFT_GROUP_BITS[3]);
+        let cb4 = create_codebook!(FFT_GROUP_CODES[4], FFT_GROUP_BITS[4]);
+        let group_cb = [cb0, cb1, cb2, cb3, cb4];
+        let level_exp_alt_cb = create_codebook!(FFT_LEVEL_EXP_ALT_CODES, FFT_LEVEL_EXP_ALT_BITS);
+        let level_exp_cb = create_codebook!(FFT_LEVEL_EXP_CODES, FFT_LEVEL_EXP_BITS);
+        let stereo_exp_cb = create_codebook!(FFT_STEREO_EXP_CODES, FFT_STEREO_EXP_BITS);
+        let phase_diff_cb = create_codebook!(FFT_STEREO_PHASE_CODES, FFT_STEREO_PHASE_BITS);
+        Self {
+            group_cb, level_exp_alt_cb, level_exp_cb,
+            stereo_exp_cb, phase_diff_cb,
+        }
+    }
+}
+
+#[derive(Clone,Copy)]
+struct OldTone {
+    used:       bool,
+    phase:      i32,
+    phase_add:  i32,
+    time:       u8,
+    scale:      f32,
+    cutoff:     usize,
+    grp:        u8,
+    offset:     u8,
+    freq:       u16,
+    ch:         u8,
+}
+
+struct Synth {
+    rdft:               RDFT,
+    sbuf:               [[FFTComplex; 256]; 2],
+    delay:              [[f32; 256]; 2],
+}
+
+impl Synth {
+    fn new() -> Self {
+        Self {
+            rdft:           RDFTBuilder::new_rdft(256, true, true),
+            sbuf:           [[FFTC_ZERO; 256]; 2],
+            delay:          [[0.0; 256]; 2],
+        }
+    }
+    fn new_sf(&mut self) {
+        self.sbuf = [[FFTC_ZERO; 256]; 2];
+    }
+    fn synth_old_tone(&mut self, tone: &mut OldTone) {
+        let off = tone.offset as usize;
+        let scale = tone.scale * TONE_ENVELOPE[tone.grp as usize][tone.time as usize];
+        tone.phase += tone.phase_add;
+
+        let val = FFTComplex::exp((tone.phase as f32) * PI / 256.0).scale(scale);
+        let ch = tone.ch as usize;
+
+        if tone.grp >= 3 || tone.cutoff >= 3 {
+            self.sbuf[ch][off]     += val;
+            self.sbuf[ch][off + 1] -= val;
+        } else {
+            let tab = &FFT_TONE_SAMPLES[tone.grp as usize][(tone.freq as usize) - (off << (4 - tone.grp))];
+            let wave = [tab[3] - tab[0], -tab[4], 1.0 - tab[2] - tab[3],
+                        tab[1] + tab[4] - 1.0, tab[0] - tab[1], tab[2]];
+            let cidx = CUTOFF_INDICES[tone.cutoff];
+            let coff0 = (off as isize) + (cidx[0] as isize);
+            let coff1 = (off as isize) + (cidx[1] as isize);
+            if coff0 >= 0 {
+                let imw = if tone.cutoff == 0 { -wave[0] } else { wave[0] };
+                self.sbuf[ch][coff0 as usize].re += val.re * wave[0];
+                self.sbuf[ch][coff0 as usize].im += val.im * imw;
+            }
+            if coff1 >= 0 {
+                let imw = if tone.cutoff <= 1 { -wave[1] } else { wave[1] };
+                self.sbuf[ch][coff1 as usize].re += val.re * wave[1];
+                self.sbuf[ch][coff1 as usize].im += val.im * imw;
+            }
+            for i in 0..4 {
+                self.sbuf[ch][off + i] += val.scale(wave[i + 2]);
+            }
+        }
+        tone.time += 1;
+        if tone.time >= (1 << (5 - tone.grp)) - 1 {
+            tone.used = false;
+        }
+    }
+    fn synth_tone(&mut self, tone: &mut Tone, cutoff: usize, scale: f32, off: usize, grp: usize) -> Option<OldTone> {
+        let mut old_tone = OldTone {
+                used:       true,
+                phase:      64 * i32::from(tone.phase) - (off as i32) * 256 - 128,
+                phase_add:  (2 * i32::from(tone.freq) + 1) << (grp + 3),
+                grp:        grp as u8,
+                time:       0,
+                scale,
+                cutoff,
+                offset:     off as u8,
+                ch:         tone.ch,
+                freq:       tone.freq,
+            };
+        self.synth_old_tone(&mut old_tone);
+        if old_tone.used {
+            Some(old_tone)
+        } else {
+            None
+        }
+    }
+    fn synth_tone4(&mut self, tone: Tone, scale: f32) {
+        let ch = tone.ch as usize;
+        let val = FFTComplex::exp(f32::from(tone.phase) * PI * 0.25).scale(scale);
+        let offset = tone.freq as usize;
+        self.sbuf[ch][offset]     += val;
+        self.sbuf[ch][offset + 1] -= val;
+    }
+    fn synth_rdft(&mut self, dst: &mut [f32], ch: usize, len: usize) {
+        self.sbuf[ch][0].re *= 2.0;
+        self.sbuf[ch][0].im  = 0.0;
+        self.rdft.do_rdft_inplace(&mut self.sbuf[ch]);
+        let scale = 1.0 / 2.0;
+        for ((src, dly), dst) in self.sbuf[ch].iter().take(len / 2).zip(self.delay[ch].chunks(2)).zip(dst.chunks_mut(2)) {
+            dst[0] += src.re * scale + dly[0];
+            dst[1] += src.im * scale + dly[1];
+        }
+        for (src, dly) in self.sbuf[ch].iter().skip(len / 2).take(len / 2).zip(self.delay[ch].chunks_mut(2)) {
+            dly[0] = src.re * scale;
+            dly[1] = src.im * scale;
+        }
+    }
+}
+
+pub struct QDM2FFT {
+    cbs:                Codebooks,
+    synth:              Synth,
+    packet_size:        usize,
+    frame_size:         usize,
+    channels:           usize,
+    subsampling:        u8,
+    freq_range:         usize,
+
+    fft_levels:         [u8; 6],
+
+    tones:              [Vec<Tone>; 5],
+    tone_start:         [usize; 5],
+    old_tones:          Vec<OldTone>,
+
+    pub is_intra:       bool,
+    frame_bits:         u8,
+}
+
+impl QDM2FFT {
+    pub fn new() -> Self {
+        Self {
+            cbs:            Codebooks::new(),
+            synth:          Synth::new(),
+            packet_size:    0,
+            frame_size:     0,
+            channels:       0,
+            subsampling:    0,
+            freq_range:     0,
+
+            fft_levels:     [0; 6],
+            tones:          [Vec::with_capacity(MAX_TONES),
+                             Vec::with_capacity(MAX_TONES),
+                             Vec::with_capacity(MAX_TONES),
+                             Vec::with_capacity(MAX_TONES),
+                             Vec::with_capacity(MAX_TONES)],
+            tone_start:     [0; 5],
+            old_tones:      Vec::new(),
+
+            is_intra:       false,
+            frame_bits:     0,
+        }
+    }
+    pub fn set_params(&mut self, channels: usize, packet_size: usize, subsampling: u8) {
+        self.subsampling = subsampling;
+        self.channels = channels;
+        self.synth.rdft = RDFTBuilder::new_rdft(packet_size, false, true);
+        self.packet_size = packet_size;
+        self.frame_size = packet_size * 16;
+        self.frame_bits = (31 - (self.frame_size.leading_zeros() & 31)) as u8;
+        self.freq_range = 255 >> (2 - self.subsampling);
+    }
+    pub fn read_type_13(&mut self, br: &mut QdmBitReader) -> DecoderResult<()> {
+        for el in self.fft_levels.iter_mut() {
+            *el                 = br.read(6) as u8;
+        }
+        Ok(())
+    }
+    pub fn read_type_14(&mut self, br: &mut QdmBitReader) -> DecoderResult<()> {
+        for el in self.fft_levels.iter_mut() {
+            *el                 = br.read_code(&self.cbs.level_exp_cb)? as u8;
+        }
+        Ok(())
+    }
+    fn read_tones(&mut self, br: &mut QdmBitReader, group: usize, use_cb2: bool) -> DecoderResult<()> {
+        let group_bits = 4 - group;
+        let group_size = 1 << (self.frame_bits - (group as u8));
+        let mut freq = 1;
+        let mut pos2 = 0;
+        let mut offset = 0;
+        let level_cb = if use_cb2 { &self.cbs.level_exp_cb } else { &self.cbs.level_exp_alt_cb };
+        while freq < self.frame_size {
+            if self.is_intra {
+                let mut diff = 0;
+                while diff < 2 {
+                    diff                = br.read_code_long(&self.cbs.group_cb[group_bits])?;
+                    if diff >= 2 { break; }
+                    freq = 1;
+                    if diff == 0 {
+                        pos2    += group_size;
+                        offset  += 1 << group_bits;
+                    } else {
+                        pos2    += 8 * group_size;
+                        offset  += 8 << group_bits;
+                    }
+                    if pos2 >= self.frame_size {
+                        return Ok(());
+                    }
+                }
+                freq += (diff - 2) as usize;
+            } else {
+                let diff                = br.read_code_long(&self.cbs.group_cb[group_bits])?;
+                freq += diff as usize;
+                while freq >= group_size - 1 {
+                    freq   -= group_size - 2;
+                    pos2   += group_size;
+                    offset += 1 << group_bits;
+                }
+            }
+            if pos2 >= self.frame_size {
+                return Ok(());
+            }
+
+            let pos = freq >> group_bits;
+            if pos > LEVEL_INDEX.len() - 1 {
+                return Ok(());
+            }
+            let stereo_mode = if self.channels == 2 {
+                                        br.read(2) as u8
+                    } else { 0 };
+
+            let mut amp                 = br.read_code(&level_cb)? as i8;
+            amp += self.fft_levels[LEVEL_INDEX[pos] as usize] as i8;
+            if amp < 0 {
+                amp = 0;
+            }
+            let phase                   = br.read(3) as u8;
+            let (amp2, phase2) = if stereo_mode > 1 {
+                    let amp_diff        = br.read_code(&self.cbs.stereo_exp_cb)? as i8;
+                    let phase_diff      = br.read_code(&self.cbs.phase_diff_cb)? as i8;
+                    let mut p2 = (phase as i8) - phase_diff;
+                    if p2 < 0 { p2 += 8; }
+                    (amp - amp_diff, p2 as u8)
+                } else { (0, 0) };
+
+            if pos <= self.freq_range {
+                if self.tones[group].len() >= MAX_TONES { return Ok(()); }
+                self.tones[group].push(Tone { freq: freq as u16, offset, phase, ch: stereo_mode & 1, amp_idx: amp as u8 });
+                if stereo_mode > 1 {
+                    if self.tones[group].len() >= MAX_TONES { return Ok(()); }
+                    self.tones[group].push(Tone { freq: freq as u16, offset, phase: phase2, ch: !stereo_mode & 1, amp_idx: amp2 as u8 });
+                }
+            }
+
+            freq += 1;
+        }
+        Ok(())
+    }
+    pub fn new_frame(&mut self) {
+        for tones in self.tones.iter_mut() {
+            tones.clear();
+        }
+        self.tone_start = [0; 5];
+    }
+    pub fn read_fft_packet(&mut self, id: u8, br: &mut QdmBitReader) -> DecoderResult<()> {
+        match id {
+            17..=23 => {
+                let grp = i16::from(self.subsampling) + 4 - i16::from(id - 17);
+                if grp >= 0 && grp < 5 {
+                    self.read_tones(br, grp as usize, false)?;
+                }
+            },
+            31 => {
+                for grp in 0..5 {
+                    self.read_tones(br, grp, false)?;
+                }
+            },
+            33..=39 => {
+                let grp = i16::from(self.subsampling) + 4 - i16::from(id - 33);
+                if grp >= 0 && grp < 5 {
+                    self.read_tones(br, grp as usize, true)?;
+                }
+            },
+            46 => {
+                for el in self.fft_levels.iter_mut() {
+                    *el                 = br.read(6) as u8;
+                }
+                for grp in 0..5 {
+                    self.read_tones(br, grp, true)?;
+                }
+            },
+            _ => {},
+        };
+        Ok(())
+    }
+    pub fn generate_tones(&mut self, sf: usize) {
+        self.synth.new_sf();
+        self.old_tones.retain(|el| el.used);
+
+        for otone in self.old_tones.iter_mut() {
+            self.synth.synth_old_tone(otone);
+        }
+
+        let sf_idx = (sf + 0xE) & 0xF;
+        let scales = if self.is_intra { &TONE_SCALES[0] } else { &TONE_SCALES[1] };
+        for group in 0..4 {
+            let group_bits = 4 - group;
+            for tone in self.tones[group].iter_mut().skip(self.tone_start[group]) {
+                if (tone.offset as usize) > sf_idx {
+                    break;
+                }
+
+                let off = (tone.freq >> group_bits) as usize;
+                if off < self.freq_range {
+                    let cutoff = if off < 2 { off } else if off < 60 { 2 } else { 3 };
+                    let scale = scales[(tone.amp_idx & 0x3F) as usize];
+                    let otone = self.synth.synth_tone(tone, cutoff, scale, off, group);
+                    if let Some(otone) = otone {
+                        self.old_tones.push(otone);
+                    }
+                }
+
+                self.tone_start[group] += 1;
+            }
+        }
+        {
+            let group = 4;
+            for tone in self.tones[group].iter().skip(self.tone_start[group]) {
+                if (tone.offset as usize) > sf_idx {
+                    break;
+                }
+                let scale = scales[(tone.amp_idx & 0x3F) as usize];
+                self.synth.synth_tone4(*tone, scale);
+                self.tone_start[group] += 1;
+            }
+        }
+    }
+    pub fn synth(&mut self, dst: &mut [f32], ch: usize) {
+        self.synth.synth_rdft(dst, ch, self.packet_size);
+    }
+    pub fn flush(&mut self) {
+    }
+}
+
+const FFT_GROUP_CODES: [&[u16]; 5] = [
+  &[
+    0x038E, 0x0001, 0x0000, 0x0022, 0x000A, 0x0006, 0x0012, 0x0002,
+    0x001E, 0x003E, 0x0056, 0x0016, 0x000E, 0x0032, 0x0072, 0x0042,
+    0x008E, 0x004E, 0x00F2, 0x002E, 0x0036, 0x00C2, 0x018E
+  ],
+  &[
+    0x07A4, 0x0001, 0x0020, 0x0012, 0x001C, 0x0008, 0x0006, 0x0010,
+    0x0000, 0x0014, 0x0004, 0x0032, 0x0070, 0x000C, 0x0002, 0x003A,
+    0x001A, 0x002C, 0x002A, 0x0022, 0x0024, 0x000A, 0x0064, 0x0030,
+    0x0062, 0x00A4, 0x01A4, 0x03A4
+  ],
+  &[
+    0x1760, 0x0001, 0x0000, 0x0082, 0x000C, 0x0006, 0x0003, 0x0007,
+    0x0008, 0x0004, 0x0010, 0x0012, 0x0022, 0x001A, 0x0000, 0x0020,
+    0x000A, 0x0040, 0x004A, 0x006A, 0x002A, 0x0042, 0x0002, 0x0060,
+    0x00AA, 0x00E0, 0x00C2, 0x01C2, 0x0160, 0x0360, 0x0760, 0x0F60
+  ],
+  &[
+    0x33EA, 0x0005, 0x0000, 0x000C, 0x0000, 0x0006, 0x0003, 0x0008,
+    0x0002, 0x0001, 0x0004, 0x0007, 0x001A, 0x000F, 0x001C, 0x002C,
+    0x000A, 0x001D, 0x002D, 0x002A, 0x000D, 0x004C, 0x008C, 0x006A,
+    0x00CD, 0x004D, 0x00EA, 0x020C, 0x030C, 0x010C, 0x01EA, 0x07EA,
+    0x0BEA, 0x03EA, 0x13EA
+  ],
+  &[
+    0x5282, 0x0016, 0x0000, 0x0136, 0x0004, 0x0000, 0x0007, 0x000A,
+    0x000E, 0x0003, 0x0001, 0x000D, 0x0006, 0x0009, 0x0012, 0x0005,
+    0x0025, 0x0022, 0x0015, 0x0002, 0x0076, 0x0035, 0x0042, 0x00C2,
+    0x0182, 0x00B6, 0x0036, 0x03C2, 0x0482, 0x01C2, 0x0682, 0x0882,
+    0x0A82, 0x0082, 0x0282, 0x1282, 0x3282, 0x2282
+  ]
+];
+const FFT_GROUP_BITS: [&[u8]; 5] = [
+  &[
+    10,  1,  2,  6,  4,  5,  6,  7,  6,  6,  7,  7,  8,  7,  8,  8,
+     9,  7,  8,  6,  6,  8, 10
+  ],
+  &[
+    11,  1,  6,  6,  5,  4,  3,  6,  6,  5,  6,  6,  7,  6,  6,  6,
+     6,  6,  6,  7,  8,  6,  7,  7,  7,  9, 10, 11
+  ],
+  &[
+    13,  2,  0,  8,  4,  3,  3,  3,  4,  4,  5,  5,  6,  5,  7,  7,
+     7,  7,  7,  7,  8,  8,  8,  9,  8,  8,  9,  9, 10, 11, 13, 12
+  ],
+  &[
+    14,  4,  0, 10,  4,  3,  3,  4,  4,  3,  4,  4,  5,  4,  5,  6,
+     6,  5,  6,  7,  7,  7,  8,  8,  8,  8,  9, 10, 10, 10, 10, 11,
+    12, 13, 14
+  ],
+  &[
+    15,  6,  0,  9,  3,  3,  3,  4,  4,  3,  4,  4,  5,  4,  5,  6,
+     6,  6,  6,  8,  7,  6,  8,  9,  9,  8,  9, 10, 11, 10, 11, 12,
+    12, 12, 14, 15, 14, 14
+  ]
+];
+
+const FFT_LEVEL_EXP_ALT_CODES: &[u16; 28] = &[
+    0x1EC6, 0x0006, 0x00C2, 0x0142, 0x0242, 0x0246, 0x00C6, 0x0046,
+    0x0042, 0x0146, 0x00A2, 0x0062, 0x0026, 0x0016, 0x000E, 0x0005,
+    0x0004, 0x0003, 0x0000, 0x0001, 0x000A, 0x0012, 0x0002, 0x0022,
+    0x01C6, 0x02C6, 0x06C6, 0x0EC6
+];
+const FFT_LEVEL_EXP_ALT_BITS: &[u8; 28] = &[
+    13,  7,  8,  9, 10, 10, 10, 10, 10,  9,  8,  7,  6,  5,  4,  3,
+     3,  2,  3,  3,  4,  5,  7,  8,  9, 11, 12, 13
+];
+
+const FFT_LEVEL_EXP_CODES: &[u16; 20] = &[
+    0x0F24, 0x0001, 0x0002, 0x0000, 0x0006, 0x0005, 0x0007, 0x000C,
+    0x000B, 0x0014, 0x0013, 0x0004, 0x0003, 0x0023, 0x0064, 0x00A4,
+    0x0024, 0x0124, 0x0324, 0x0724
+];
+const FFT_LEVEL_EXP_BITS: &[u8; 20] = &[
+    12, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 8, 9, 10, 11, 12
+];
+
+const FFT_STEREO_EXP_CODES: &[u8; 7] = &[ 0x3E, 0x01, 0x00, 0x02, 0x06, 0x0E, 0x1E ];
+const FFT_STEREO_EXP_BITS: &[u8; 7] = &[ 6, 1, 2, 3, 4, 5, 6 ];
+
+const FFT_STEREO_PHASE_CODES: &[u8; 9] = &[
+    0x35, 0x02, 0x00, 0x01, 0x0D, 0x15, 0x05, 0x09, 0x03
+];
+const FFT_STEREO_PHASE_BITS: &[u8; 9] = &[ 6, 2, 2, 4, 4, 6, 5, 4, 2 ];
+
+const CUTOFF_INDICES: [[i8; 2]; 4] = [ [1, 2], [-1, 0], [-1,-2], [0, 0] ];
+
+const LEVEL_INDEX: [u8; 256] = [
+    0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+];
+
+const FFT_TONE_SAMPLES: [[[f32; 5]; 16]; 4] = [
+  [
+    [ 0.0100000000,-0.0037037037,-0.0020000000,-0.0069444444,-0.0018416207 ],
+    [ 0.0416666667, 0.0000000000, 0.0000000000,-0.0208333333,-0.0123456791 ],
+    [ 0.1250000000, 0.0558035709, 0.0330687836,-0.0164473690,-0.0097465888 ],
+    [ 0.1562500000, 0.0625000000, 0.0370370370,-0.0062500000,-0.0037037037 ],
+    [ 0.1996007860, 0.0781250000, 0.0462962948, 0.0022727272, 0.0013468013 ],
+    [ 0.2000000000, 0.0625000000, 0.0370370373, 0.0208333333, 0.0074074073 ],
+    [ 0.2127659619, 0.0555555556, 0.0329218097, 0.0208333333, 0.0123456791 ],
+    [ 0.2173913121, 0.0473484844, 0.0280583613, 0.0347222239, 0.0205761325 ],
+    [ 0.2173913121, 0.0347222239, 0.0205761325, 0.0473484844, 0.0280583613 ],
+    [ 0.2127659619, 0.0208333333, 0.0123456791, 0.0555555556, 0.0329218097 ],
+    [ 0.2000000000, 0.0208333333, 0.0074074073, 0.0625000000, 0.0370370370 ],
+    [ 0.1996007860, 0.0022727272, 0.0013468013, 0.0781250000, 0.0462962948 ],
+    [ 0.1562500000,-0.0062500000,-0.0037037037, 0.0625000000, 0.0370370370 ],
+    [ 0.1250000000,-0.0164473690,-0.0097465888, 0.0558035709, 0.0330687836 ],
+    [ 0.0416666667,-0.0208333333,-0.0123456791, 0.0000000000, 0.0000000000 ],
+    [ 0.0100000000,-0.0069444444,-0.0018416207,-0.0037037037,-0.0020000000 ]
+  ], [
+    [ 0.0050000000,-0.0200000000, 0.0125000000,-0.3030303030, 0.0020000000 ],
+    [ 0.1041666642, 0.0400000000,-0.0250000000, 0.0333333333,-0.0200000000 ],
+    [ 0.1250000000, 0.0100000000, 0.0142857144,-0.0500000007,-0.0200000000 ],
+    [ 0.1562500000,-0.0006250000,-0.00049382716,-0.000625000,-0.00049382716 ],
+    [ 0.1562500000,-0.0006250000,-0.00049382716,-0.000625000,-0.00049382716 ],
+    [ 0.1250000000,-0.0500000000,-0.0200000000, 0.0100000000, 0.0142857144 ],
+    [ 0.1041666667, 0.0333333333,-0.0200000000, 0.0400000000,-0.0250000000 ],
+    [ 0.0050000000,-0.3030303030, 0.0020000001,-0.0200000000, 0.0125000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ]
+  ], [
+    [ 0.1428571492, 0.1250000000,-0.0285714287,-0.0357142873, 0.0208333333 ],
+    [ 0.1818181818, 0.0588235296, 0.0333333333, 0.0212765951, 0.0100000000 ],
+    [ 0.1818181818, 0.0212765951, 0.0100000000, 0.0588235296, 0.0333333333 ],
+    [ 0.1428571492,-0.0357142873, 0.0208333333, 0.1250000000,-0.0285714287 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ]
+  ], [
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ]
+  ]
+];
+
+const TONE_ENVELOPE: [[f32; 31]; 4] = [
+  [
+    0.009607375, 0.038060248, 0.084265202, 0.146446645,
+    0.222214907, 0.308658302, 0.402454883, 0.500000060,
+    0.597545207, 0.691341758, 0.777785182, 0.853553414,
+    0.915734828, 0.961939812, 0.990392685, 1.00000000,
+    0.990392625, 0.961939752, 0.915734768, 0.853553295,
+    0.777785063, 0.691341639, 0.597545087, 0.500000000,
+    0.402454853, 0.308658272, 0.222214878, 0.146446615,
+    0.084265172, 0.038060218, 0.009607345
+  ], [
+    0.038060248, 0.146446645, 0.308658302, 0.500000060,
+    0.691341758, 0.853553414, 0.961939812, 1.00000000,
+    0.961939752, 0.853553295, 0.691341639, 0.500000000,
+    0.308658272, 0.146446615, 0.038060218, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000
+  ], [
+    0.146446645, 0.500000060, 0.853553414, 1.00000000,
+    0.853553295, 0.500000000, 0.146446615, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000
+  ], [
+    0.500000060, 1.00000000,  0.500000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000
+  ]
+];