### ----------------------------------------------------
### -- MIDI::Make
### -- Licenses: MIT
### -- Authors: Pierre-Emmanuel Lévesque <pierre.e.levesque@gmail.com>
### -- File: t/all.rakutest
### ----------------------------------------------------
### -- Chunk 1 of 2
use Test;
use Test::Selector;
use MIDI::Make;

sub test ($label, $title, &renderable, $expected-bytes) {
    t $label => {
        is(
            &renderable().render,
            Buf.new($expected-bytes.words.map({"0x$_"})».Int),
            $title,
        );
    }
}

# --------------------------------------------------------------------
# Song class

test('s1',
    'Trackless Song Instantiation',
    { Song.new },
    '4D 54 68 64 00 00 00 06
     00 01 00 00 00 30',
);

test('s2',
    'Trackless Song Instantiation: format => 0',
    { Song.new(:format(0)) },
    '4D 54 68 64 00 00 00 06
     00 00 00 00 00 30',
);

test('s3',
    'Trackless Song Instantiation: time-division => "frame"',
    { Song.new(:time-division('frame')) },
    '4D 54 68 64 00 00 00 06
     00 01 00 00 E8 04',
);

test('s4',
    'Trackless Song Instantiation: PPQ => 300',
    { Song.new(:PPQ(300)) },
    '4D 54 68 64 00 00 00 06
     00 01 00 00 01 2C',
);

test('s5',
    'Trackless Song Instantiation: FPS => 29.97',
    { Song.new(:time-division('frame'), :FPS(29.97)) },
    '4D 54 68 64 00 00 00 06
     00 01 00 00 E3 04',
);

test('s6',
    'Trackless Song Instantiation: PPF => 8',
    { Song.new(:time-division('frame'), :PPF(24)) },
    '4D 54 68 64 00 00 00 06
     00 01 00 00 E8 18',
);

test('s7',
    'Trackless Song: Set params after instantiation A',
    {
        my \s = Song.new;
        s.format: 2;
        s.PPQ: 425;
        s;
    },
    '4D 54 68 64 00 00 00 06
     00 02 00 00 01 A9',
);

test('s8',
    'Trackless Song: Set params after instantiation B',
    {
        my \s = Song.new;
        s.format: 1;
        s.time-division: 'frame';
        s.FPS: 30;
        s.PPF: 48;
        s;
    },
    '4D 54 68 64 00 00 00 06
     00 01 00 00 E2 30',
);

# --------------------------------------------------------------------
# Track class

test('t1',
    'Track Instantiation',
    { Track.new },
    '4D 54 72 6B 00 00 00 04
     00 FF 2F 00',
);

test('t2',
    'Track Instantiation: copyright => "c 2022 anonymous"',
    { Track.new(:copyright('c 2022 anonymous')) },
    '4D 54 72 6B 00 00 00 18
     00 FF 02 10 63 20 32 30 32 32 20 61 6E 6F 6E 79 6D 6F 75 73
     00 FF 2F 00',
);

test('t3',
    'Track Instantiation: name => "melody"',
    { Track.new(:name('melody')) },
    '4D 54 72 6B 00 00 00 0E
     00 FF 03 06 6D 65 6C 6F 64 79
     00 FF 2F 00',
);

test('t4',
    'Track Instantiation: delta-time => 100',
    {
        my \t = Track.new(:delta-time(100));
        t.note-on: 60;
        t;
    },
    '4D 54 72 6B 00 00 00 08
     64 90 3C 7F
     00 FF 2F 00',
);

test('t5',
    'Track Instantiation: channel => 1',
    {
        my \t = Track.new(:channel(1));
        t.note-on: 60;
        t;
    },
    '4D 54 72 6B 00 00 00 08
     00 91 3C 7F
     00 FF 2F 00',
);

test('t6',
    'Track Instantiation: velocity-off => 10',
    {
        my \t = Track.new(:velocity-off(10));
        t.note-off: 60;
        t;
    },
    '4D 54 72 6B 00 00 00 08
     00 80 3C 0A
     00 FF 2F 00',
);

test('t7',
    'Track Instantiation: velocity-on => 100',
    {
        my \t = Track.new(:velocity-on(100));
        t.note-on: 60;
        t;
    },
    '4D 54 72 6B 00 00 00 08
     00 90 3C 64
     00 FF 2F 00',
);

test('t8',
    'Track: Change params after instantiation',
    {
        my \t = Track.new;
        t.delta-time: 100;
        t.channel: 1;
        t.velocity-off: 10;
        t.velocity-on:  100;
        t.note-on:  60;
        t.note-off: 60;
        t;
    },
    '4D 54 72 6B 00 00 00 0C
     64 91 3C 64
     00 81 3C 0A
     00 FF 2F 00',
);

test('t9',
    'Track: copyright',
    {
        my \t = Track.new;
	    t.copyright: 'c 2022 anonymous';
	    t;
    },
    '4D 54 72 6B 00 00 00 18
     00 FF 02 10 63 20 32 30 32 32 20 61 6E 6F 6E 79 6D 6F 75 73
     00 FF 2F 00',
);

test('t10',
    'Track: copyright with ignored delta-time',
    {
        my \t = Track.new;
        t.delta-time: 100; # Ignored.
	    t.copyright: 'c 2022 anonymous';
	    t;
    },
    '4D 54 72 6B 00 00 00 18
     00 FF 02 10 63 20 32 30 32 32 20 61 6E 6F 6E 79 6D 6F 75 73
     64 FF 2F 00',
);

test('t11',
    'Track: name',
    {
        my \t = Track.new;
	    t.name: 'melody';
	    t;
    },
    '4D 54 72 6B 00 00 00 0E
     00 FF 03 06 6D 65 6C 6F 64 79
     00 FF 2F 00',
);

test('t12',
    'Track: name with ignored delta-time',
    {
        my \t = Track.new;
        t.delta-time: 100; # Ignored.
	    t.name: 'melody';
	    t;
    },
    '4D 54 72 6B 00 00 00 0E
     00 FF 03 06 6D 65 6C 6F 64 79
     64 FF 2F 00',
);

test('t13',
    'Track: instrument',
    {
        my \t = Track.new;
	    t.instrument: 'piano';
	    t;
    },
    '4D 54 72 6B 00 00 00 0D
     00 FF 04 05 70 69 61 6E 6F
     00 FF 2F 00',
);

test('t14',
    'Track: text',
    {
        my \t = Track.new;
	    t.text: 'Lorem ipsum dolor sit amet.';
	    t;
    },
    '4D 54 72 6B 00 00 00 23
     00 FF 01 1B 4C 6F 72 65 6D 20 69 70 73 75 6D 20 64 6F 6C 6F 72 20
      73 69 74 20 61 6D 65 74 2E
     00 FF 2F 00',
);

test('t15',
    'Track: lyric',
    {
        my \t = Track.new;
	    t.lyric: 'one';
	    t;
    },
    '4D 54 72 6B 00 00 00 0B
     00 FF 05 03 6F 6E 65
     00 FF 2F 00',
);

test('t16',
    'Track: marker',
    {
        my \t = Track.new;
	    t.marker: 'section I';
	    t;
    },
    '4D 54 72 6B 00 00 00 11
     00 FF 06 09 73 65 63 74 69 6F 6E 20 49
     00 FF 2F 00',
);

test('t17',
    'Track: cue',
    {
        my \t = Track.new;
	    t.cue: 'door slam';
	    t;
    },
    '4D 54 72 6B 00 00 00 11
     00 FF 07 09 64 6F 6F 72 20 73 6C 61 6D
     00 FF 2F 00',
);

test('t18',
    'Track: program-name',
    {
        my \t = Track.new;
	    t.program-name: 'electric piano';
	    t;
    },
    '4D 54 72 6B 00 00 00 16
     00 FF 08 0E 65 6C 65 63 74 72 69 63 20 70 69 61 6E 6F
     00 FF 2F 00',
);

test('t19',
    'Track: port',
    {
        my \t = Track.new;
	    t.port: 'MIDI Out 1';
	    t;
    },
    '4D 54 72 6B 00 00 00 12
     00 FF 09 0A 4D 49 44 49 20 4F 75 74 20 31
     00 FF 2F 00',
);

test('t20',
    'Track: tempo with default params',
    {
        my \t = Track.new;
	    t.tempo;
	    t;
    },
    '4D 54 72 6B 00 00 00 0B
     00 FF 51 03 07 A1 20
     00 FF 2F 00',
);

test('t21',
    'Track: tempo with custom params',
    {
        my \t = Track.new;
	    t.tempo: 10250;
	    t;
    },
    '4D 54 72 6B 00 00 00 0B
     00 FF 51 03 00 28 0A
     00 FF 2F 00',
);

test('t22',
    'Track: time-signature with default params',
    {
        my \t = Track.new;
	    t.time-signature;
	    t;
    },
    '4D 54 72 6B 00 00 00 0C
     00 FF 58 04 04 02 18 08
     00 FF 2F 00',
);

test('t23',
    'Track: time-signature with custom params',
    {
        my \t = Track.new;
	    t.time-signature: 2\8, 32, 4;
	    t;
    },
    '4D 54 72 6B 00 00 00 0C
     00 FF 58 04 02 03 20 04
     00 FF 2F 00',
);

test('t24',
    'Track: key-signature',
    {
        my \t = Track.new;
	    t.key-signature: -7;
        t.key-signature: -6;
        t.key-signature: -5;
        t.key-signature: -4;
	    t.key-signature: -3;
        t.key-signature: -2;
        t.key-signature: -1;
        t.key-signature: 0, 1;
        t.key-signature: 1, 1;
        t.key-signature: 2, 1;
        t.key-signature: 3, 1;
        t.key-signature: 4, 1;
        t.key-signature: 5, 1;
        t.key-signature: 6, 1;
        t.key-signature: 7, 1;
	    t;
    },
    '4D 54 72 6B 00 00 00 5E
     00 FF 59 02 F9 00
     00 FF 59 02 FA 00
     00 FF 59 02 FB 00
     00 FF 59 02 FC 00
     00 FF 59 02 FD 00
     00 FF 59 02 FE 00
     00 FF 59 02 FF 00
     00 FF 59 02 00 01
     00 FF 59 02 01 01
     00 FF 59 02 02 01
     00 FF 59 02 03 01
     00 FF 59 02 04 01
     00 FF 59 02 05 01
     00 FF 59 02 06 01
     00 FF 59 02 07 01
     00 FF 2F 00',
);

test('t25',
    'Track: key-signature using ♭/♯ postfix for accidentals',
    {
        my \t = Track.new;
	    t.key-signature: 7♭;
        t.key-signature: 6♭;
        t.key-signature: 5♭;
        t.key-signature: 4♭;
	    t.key-signature: 3♭;
        t.key-signature: 2♭;
        t.key-signature: 1♭;
        t.key-signature: 0♭, 1;
        t.key-signature: 0♯, 1;
        t.key-signature: 1♯, 1;
        t.key-signature: 2♯, 1;
        t.key-signature: 3♯, 1;
        t.key-signature: 4♯, 1;
        t.key-signature: 5♯, 1;
        t.key-signature: 6♯, 1;
        t.key-signature: 7♯, 1;
	    t;
    },
    '4D 54 72 6B 00 00 00 64
     00 FF 59 02 F9 00
     00 FF 59 02 FA 00
     00 FF 59 02 FB 00
     00 FF 59 02 FC 00
     00 FF 59 02 FD 00
     00 FF 59 02 FE 00
     00 FF 59 02 FF 00
     00 FF 59 02 00 01
     00 FF 59 02 00 01
     00 FF 59 02 01 01
     00 FF 59 02 02 01
     00 FF 59 02 03 01
     00 FF 59 02 04 01
     00 FF 59 02 05 01
     00 FF 59 02 06 01
     00 FF 59 02 07 01
     00 FF 2F 00',
);

test('t26',
    'Track: key-signature using Modes enums',
    {
        my \t = Track.new;
        t.key-signature: 0, major;
        t.key-signature: 0, minor;
	    t;
    },
    '4D 54 72 6B 00 00 00 10
     00 FF 59 02 00 00
     00 FF 59 02 00 01
     00 FF 2F 00',
);

test('t27',
    'Track: note-on and note-off',
    {
        my \t = Track.new;
        t.note-on:  60;
        t.note-off: 60;
        t.note-on:  127, 100;
        t.note-off: 127, 10;
        t.note-on:  60;
        t.note-off: 60;
        t.velocity-on: 100;
        t.velocity-off: 10;
        t.note-on:  60;
        t.note-off: 60;
        t;
    },
    '4D 54 72 6B 00 00 00 24
     00 90 3C 7F
     00 80 3C 00
     00 90 7F 64
     00 80 7F 0A
     00 90 3C 7F
     00 80 3C 00
     00 90 3C 64
     00 80 3C 0A
     00 FF 2F 00',
);

test('t28',
    'Track: note aftertouch',
    {
        my \t = Track.new;
        t.aftertouch: 100, 53;
        t;
    },
    '4D 54 72 6B 00 00 00 08
     00 A0 35 64
     00 FF 2F 00',
);

test('t29',
    'Track: channel aftertouch',
    {
        my \t = Track.new;
        t.aftertouch: 100;
        t;
    },
    '4D 54 72 6B 00 00 00 07
     00 D0 64
     00 FF 2F 00',
);

test('t30',
    'Track: controller',
    {
        my \t = Track.new;
        t.controller: 8, 100;
        t;
    },
    '4D 54 72 6B 00 00 00 08
     00 B0 08 64
     00 FF 2F 00',
);

test('t31',
    'Track: controller shortcuts',
    {
        my \t = Track.new;
        t.bank-select_MSB:         0;
        t.modulation_MSB:          1;
        t.breath_MSB:              2;
            # 3 is undefined.
        t.foot-pedal_MSB:          4;
        t.portamento-time_MSB:     5;
        t.data-entry_MSB:          6;
        t.channel-volume_MSB:      7;
        t.balance_MSB:             8;
            # 9 is undefined.
        t.pan_MSB:                10;
        t.expression_MSB:         11;
        t.effect-control_1_MSB:   12;
        t.effect-control_2_MSB:   13;
            # 14-15 are undefined.
        t.general-control_1_MSB:  16;
        t.general-control_2_MSB:  17;
        t.general-control_3_MSB:  18;
        t.general-control_4_MSB:  19;
            # 20-31 are undefined.
        t.bank-select_LSB:        32;
        t.modulation_LSB:         33;
        t.breath_LSB:             34;
            # 35 is undefined.
        t.foot-pedal_LSB:         36;
        t.portamento-time_LSB:    37;
        t.data-entry_LSB:         38;
        t.channel-volume_LSB:     39;
        t.balance_LSB:            40;
            # 41 is undefined.
        t.pan_LSB:                42;
        t.expression_LSB:         43;
        t.effect-control_1_LSB:   44;
        t.effect-control_2_LSB:   45;
            # 46-47 are undefined.
        t.general-control_1_LSB:  48;
        t.general-control_2_LSB:  49;
        t.general-control_3_LSB:  50;
        t.general-control_4_LSB:  51;
            # 52-63 are undefined.
        t.hold_1-pedal:           64;
        t.portamento:             65;
        t.sostenuto:              66;
        t.soft-pedal:             67;
        t.legato-footswitch:      68;
        t.hold_2-pedal:           69;
        t.sound-control_1:        70;
        t.sound-control_2:        71;
        t.sound-control_3:        72;
        t.sound-control_4:        73;
        t.sound-control_5:        74;
        t.sound-control_6:        75;
        t.sound-control_7:        76;
        t.sound-control_8:        77;
        t.sound-control_9:        78;
        t.sound-control_10:       79;
        t.general-control_5:      80;
        t.general-control_6:      81;
        t.general-control_7:      82;
        t.general-control_8:      83;
        t.portamento-control:     84;
            # 85-87 are undefined.
        t.hi-res-velocity-prefix: 88;
            # 89-90 are undefined.
        t.effect_1-depth:         91;
        t.effect_2-depth:         92;
        t.effect_3-depth:         93;
        t.effect_4-depth:         94;
        t.effect_5-depth:         95;
        t.data-increment:         96;
        t.data-decrement:         97;
        t.NRPN_LSB:               98;
        t.NRPN_MSB:               99;
        t.RPN_LSB:               100;
        t.RPN_MSB:               101;
             # 102-119 are undefined.
        t.all-sounds-off:        120;
        t.reset-controllers:     121;
        t.local-switch:          122;
        t.all-notes-off:         123;
        t.omni-mode-off:         124;
        t.omni-mode-on:          125;
        t.mono-mode:             126;
        t.poly-mode:             127;
        t;
    },
    '4D 54 72 6B 00 00 01 28
     00 B0 00 00
     00 B0 01 01
     00 B0 02 02
     00 B0 04 04
     00 B0 05 05
     00 B0 06 06
     00 B0 07 07
     00 B0 08 08
     00 B0 0A 0A
     00 B0 0B 0B
     00 B0 0C 0C
     00 B0 0D 0D
     00 B0 10 10
     00 B0 11 11
     00 B0 12 12
     00 B0 13 13
     00 B0 20 20
     00 B0 21 21
     00 B0 22 22
     00 B0 24 24
     00 B0 25 25
     00 B0 26 26
     00 B0 27 27
     00 B0 28 28
     00 B0 2A 2A
     00 B0 2B 2B
     00 B0 2C 2C
     00 B0 2D 2D
     00 B0 30 30
     00 B0 31 31
     00 B0 32 32
     00 B0 33 33
     00 B0 40 40
     00 B0 41 41
     00 B0 42 42
     00 B0 43 43
     00 B0 44 44
     00 B0 45 45
     00 B0 46 46
     00 B0 47 47
     00 B0 48 48
     00 B0 49 49
     00 B0 4A 4A
     00 B0 4B 4B
     00 B0 4C 4C
     00 B0 4D 4D
     00 B0 4E 4E
     00 B0 4F 4F
     00 B0 50 50
     00 B0 51 51
     00 B0 52 52
     00 B0 53 53
     00 B0 54 54
     00 B0 58 58
     00 B0 5B 5B
     00 B0 5C 5C
     00 B0 5D 5D
     00 B0 5E 5E
     00 B0 5F 5F
     00 B0 60 60
     00 B0 61 61
     00 B0 62 62
     00 B0 63 63
     00 B0 64 64
     00 B0 65 65
     00 B0 78 78
     00 B0 79 79
     00 B0 7A 7A
     00 B0 7B 7B
     00 B0 7C 7C
     00 B0 7D 7D
     00 B0 7E 7E
     00 B0 7F 7F
     00 FF 2F 00',
);

test('t32',
    'Track: controller shortcuts (combined)',
    {
        my \t = Track.new;
        t.bank-select:         32;
        t.modulation:         133;
        t.breath:             234;
            # 3 is undefined.
        t.foot-pedal:         436;
        t.portamento-time:    537;
        t.data-entry:         638;
        t.channel-volume:     739;
        t.balance:            840;
            # 9 is undefined.
        t.pan:               1042;
        t.expression:        1143;
        t.effect-control_1:  1244;
        t.effect-control_2:  1345;
            # 14-15 are undefined.
        t.general-control_1: 1648;
        t.general-control_2: 1749;
        t.general-control_3: 1850;
        t.general-control_4: 1951;
        t;
    },
    '4D 54 72 6B 00 00 00 84
     00 B0 00 00
     00 B0 20 20
     00 B0 01 01
     00 B0 21 05
     00 B0 02 01
     00 B0 22 6A
     00 B0 04 03
     00 B0 24 34
     00 B0 05 04
     00 B0 25 19
     00 B0 06 04
     00 B0 26 7E
     00 B0 07 05
     00 B0 27 63
     00 B0 08 06
     00 B0 28 48
     00 B0 0A 08
     00 B0 2A 12
     00 B0 0B 08
     00 B0 2B 77
     00 B0 0C 09
     00 B0 2C 5C
     00 B0 0D 0A
     00 B0 2D 41
     00 B0 10 0C
     00 B0 30 70
     00 B0 11 0D
     00 B0 31 55
     00 B0 12 0E
     00 B0 32 3A
     00 B0 13 0F
     00 B0 33 1F
     00 FF 2F 00',
);

test('t33',
    'Track: program-change',
    {
        my \t = Track.new;
        t.program-change: 100;
        t;
    },
    '4D 54 72 6B 00 00 00 07
     00 C0 64
     00 FF 2F 00',
);

test('t34',
    'Track: pitch-bend with default param, on channel 1',
    {
        my \t = Track.new;
        t.channel: 1;
	    t.pitch-bend;
	    t;
    },
    '4D 54 72 6B 00 00 00 08
     00 E1 00 40
     00 FF 2F 00',
);

test('t35',
    'Track: pitch-bend => none',
    {
        my \t = Track.new;
	    t.pitch-bend: 8192;
	    t;
    },
    '4D 54 72 6B 00 00 00 08
     00 E0 00 40
     00 FF 2F 00',
);

test('t36',
    'Track: pitch-bend => lowest',
    {
        my \t = Track.new;
	    t.pitch-bend: 0;
	    t;
    },
    '4D 54 