jevstrudel.git / packages / core / test / signal.test.mjs
1/*
2signal.test.mjs - <short description TODO>
3Copyright (C) 2022 Strudel contributors - see <https://codeberg.org/uzu/strudel/src/branch/main/packages/core/test/pattern.test.mjs>
4This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program.  If not, see <https://www.gnu.org/licenses/>.
5*/
6
7import Fraction from 'fraction.js';
8
9import { describe, it, expect, vi } from 'vitest';
10
11import {
12  saw,
13  saw2,
14  isaw,
15  isaw2,
16  tri,
17  tri2,
18  itri,
19  itri2,
20  square,
21  square2,
22  isquare,
23  isquare2,
24  per,
25  perx,
26  cyclesPer,
27} from '../signal.mjs';
28import { fastcat, sequence, State, TimeSpan, Hap, note } from '../index.mjs';
29
30const st = (begin, end) => new State(ts(begin, end));
31const ts = (begin, end) => new TimeSpan(Fraction(begin), Fraction(end));
32const hap = (whole, part, value, context = {}) => new Hap(whole, part, value, context);
33
34const third = Fraction(1, 3);
35const twothirds = Fraction(2, 3);
36
37const sameFirst = (a, b) => {
38  return expect(a.sortHapsByPart().firstCycle()).toStrictEqual(b.sortHapsByPart().firstCycle());
39};
40
41describe('signal()', () => {
42  it('Can make saw/saw2', () => {
43    expect(saw.struct(true, true, true, true).firstCycle()).toStrictEqual(sequence(0, 0.25, 0.5, 0.75).firstCycle());
44    expect(saw2.struct(true, true, true, true).firstCycle()).toStrictEqual(sequence(-1, -0.5, 0, 0.5).firstCycle());
45  });
46  it('Can make isaw/isaw2', () => {
47    expect(isaw.struct(true, true, true, true).firstCycle()).toStrictEqual(sequence(1, 0.75, 0.5, 0.25).firstCycle());
48    expect(isaw2.struct(true, true, true, true).firstCycle()).toStrictEqual(sequence(1, 0.5, 0, -0.5).firstCycle());
49  });
50  it('Can make tri/tri2', () => {
51    expect(tri.struct(true, true, true, true).firstCycle()).toStrictEqual(sequence(0, 0.5, 1, 0.5).firstCycle());
52    expect(tri2.struct(true, true, true, true).firstCycle()).toStrictEqual(sequence(-1, 0, 1, 0).firstCycle());
53  });
54  it('Can make itri/itri2', () => {
55    expect(itri.struct(true, true, true, true).firstCycle()).toStrictEqual(sequence(1, 0.5, 0, 0.5).firstCycle());
56    expect(itri2.struct(true, true, true, true).firstCycle()).toStrictEqual(sequence(1, 0, -1, 0).firstCycle());
57  });
58  it('Can make square/square2', () => {
59    expect(square.struct(true, true, true, true).firstCycle()).toStrictEqual(sequence(0, 0, 1, 1).firstCycle());
60    expect(square2.struct(true, true, true, true).firstCycle()).toStrictEqual(sequence(-1, -1, 1, 1).firstCycle());
61  });
62  it('Can make isquare/isquare2', () => {
63    expect(isquare.struct(true, true, true, true).firstCycle()).toStrictEqual(sequence(1, 1, 0, 0).firstCycle());
64    expect(isquare2.struct(true, true, true, true).firstCycle()).toStrictEqual(sequence(1, 1, -1, -1).firstCycle());
65  });
66  it('Can go into negative time', () => {
67    expect(saw.late(1).struct(true, true, true, true).firstCycle()).toStrictEqual(
68      sequence(0, 0.25, 0.5, 0.75).firstCycle(),
69    );
70    expect(saw2.late(1).struct(true, true, true, true).firstCycle()).toStrictEqual(
71      sequence(-1, -0.5, 0, 0.5).firstCycle(),
72    );
73    expect(isaw.late(1).struct(true, true, true, true).firstCycle()).toStrictEqual(
74      sequence(1, 0.75, 0.5, 0.25).firstCycle(),
75    );
76    expect(isaw2.late(1).struct(true, true, true, true).firstCycle()).toStrictEqual(
77      sequence(1, 0.5, 0, -0.5).firstCycle(),
78    );
79    expect(tri.late(1).struct(true, true, true, true).firstCycle()).toStrictEqual(
80      sequence(0, 0.5, 1, 0.5).firstCycle(),
81    );
82    expect(tri2.late(1).struct(true, true, true, true).firstCycle()).toStrictEqual(sequence(-1, 0, 1, 0).firstCycle());
83    expect(itri.late(1).struct(true, true, true, true).firstCycle()).toStrictEqual(
84      sequence(1, 0.5, 0, 0.5).firstCycle(),
85    );
86    expect(itri2.late(1).struct(true, true, true, true).firstCycle()).toStrictEqual(sequence(1, 0, -1, 0).firstCycle());
87    expect(square.late(1).struct(true, true, true, true).firstCycle()).toStrictEqual(sequence(0, 0, 1, 1).firstCycle());
88    expect(square2.late(1).struct(true, true, true, true).firstCycle()).toStrictEqual(
89      sequence(-1, -1, 1, 1).firstCycle(),
90    );
91    expect(isquare.late(1).struct(true, true, true, true).firstCycle()).toStrictEqual(
92      sequence(1, 1, 0, 0).firstCycle(),
93    );
94    expect(isquare2.late(1).struct(true, true, true, true).firstCycle()).toStrictEqual(
95      sequence(1, 1, -1, -1).firstCycle(),
96    );
97  });
98});
99
100describe('cyclesPer', () => {
101  it('gives cycles per hap', () => {
102    sameFirst(
103      cyclesPer.struct(true, true, true, fastcat(true, true)),
104      sequence(0.25, 0.25, 0.25, fastcat(0.125, 0.125)).fmap(Fraction),
105    );
106  });
107});
108describe('per', () => {
109  it('gives haps per cycle', () => {
110    sameFirst(per.struct(true, true, true, fastcat(true, true)), sequence(4, 4, 4, fastcat(8, 8)).fmap(Fraction));
111  });
112});
113
114describe('perx', () => {
115  it('gives exponential haps per cycle', () => {
116    sameFirst(
117      perx.struct(true, true, true, fastcat(true, fastcat(true, true))),
118      sequence(3, 3, 3, fastcat(4, fastcat(5, 5))),
119    );
120  });
121});
122
123describe('shuffle', () => {
124  it('returns original pattern if input is 1', () => {
125    expect(note('c d e f').sound('piano').shuffle(1).firstCycle()).toEqual(note('c d e f').sound('piano').firstCycle());
126  });
127});