mirror of
https://github.com/zeldaret/oot.git
synced 2025-02-27 03:24:45 +00:00
* add defines for sequence opcodes * name aseq_cmd_id defines from the corresponding macro names * ASEQ_CMD_ID_ -> ASEQ_OPC_ * remove previous opcode defines * ASEQ_OPC_LAYER_STEP3_ -> ASEQ_OPC_LAYER_ * sync with MM and fixups * format * ASEQ_OPC_ -> ASEQ_OP_ * ASEQ_OP_CTRLFLOW_ -> ASEQ_OP_ * tab-align * ASEQ_OP_SEQUENCE_ -> ASEQ_OP_SEQ_ * ASEQ_OP_CHANNEL_ -> ASEQ_OP_CHAN_ * define MML_VERSION in the Makefile for seqplayer.c
2517 lines
63 KiB
GAS
2517 lines
63 KiB
GAS
/**
|
|
* @file aseq.h
|
|
* Zelda64 Music Macro Language (MML) Assembler Definitions
|
|
*
|
|
* This file implements the assembler for Zelda64 Music Macro Language. MML is an interpreted language that combines
|
|
* general MIDI with arithmetic and control flow instructions.
|
|
*
|
|
* There are multiple distinct sections:
|
|
* - .sequence: The top level of the program, this is unique and executes sequentially.
|
|
* - .channel: Spawned by the top-level sequence, there can be up to 16 channels active at any time that execute in
|
|
* parallel. Channels map directly to MIDI channels, control changes made in channels affect the notes
|
|
* in the layers spawned by the channel.
|
|
* - .layer: Spawned by channels, up to 4 layers per channel. These execute in parallel. The purpose of layers is
|
|
* to allow overlapping notes.
|
|
* - .table: Contains dyntable labels.
|
|
* - .array: Contains array-like data that can be read using sequence IO instructions.
|
|
* - .filter: Contains filter structures.
|
|
* - .envelope: Contains envelope scripts.
|
|
* - .buffer: Contains arbitrary data.
|
|
*
|
|
* Execution begins in the sequence section at position 0 of the sequence with no channels or layers initialized.
|
|
*
|
|
* Execution flows until it blocks on certain commands that induce delays for a fixed number of ticks (it is to be
|
|
* understood that ticks in this context refers to seqTicks in code), such as the delay instructions or note
|
|
* instructions. If this happens in a channel or layer, the other channels/layers will continue execution until they
|
|
* hit their own delays.
|
|
*
|
|
* Sequences can self-modify. The ldseq, stseq and related instructions can perform loads and stores to any location
|
|
* in a sequence, including the executable sections. This can be used to make up for the lack of registers and
|
|
* arithmetic instructions by replacing immediate values in the instructions themselves.
|
|
*
|
|
* The maximum call depth is 4. Call depth applies to both loops and subroutines. Loops are implemented like
|
|
* subroutines in that starting a loop pushes a return address onto the call stack and reaching the end of the loop
|
|
* decrements the loop counter. If the loop has iterations left, it jumps to the return address. When a loop completes
|
|
* all the iterations, or when the break instruction is executed, the return address is popped from the call stack and
|
|
* no jump occurs.
|
|
*
|
|
* In the instruction descriptions, we use a number of conventions for referring to various internal state:
|
|
* - PC : The location of the current instruction, within the respective sequence/channel/layer
|
|
* - SEQ : The sequence data, viewed as an array of s8/u8
|
|
* - TR : Temporary s8 register
|
|
* - TP : Temporary u16 register
|
|
* - CIO[15..0][7..0] : Channel IO
|
|
* - SIO[7..0] : Sequence IO
|
|
* - DYNTBL : Current dyntable, DYNTBL16 and DYNTBL8 are different views into the same memory
|
|
* - DYNTBL16 : Current dyntable, viewed as an array of s16/u16
|
|
* - DYNTBL8 : Current dyntable, viewed as an array of s8/u8
|
|
* - CALLDEPTH : The current subroutine nesting level
|
|
* - SHORTVELTBL : Current short notes velocity table
|
|
* - SHORTGATETBL : Current short notes gate time table
|
|
*/
|
|
#ifndef ASEQ_H
|
|
#define ASEQ_H
|
|
|
|
/**
|
|
* MML Version
|
|
*/
|
|
|
|
#ifndef MML_VERSION
|
|
#error "MML version not defined, define MML_VERSION in the cpp invocation"
|
|
#endif
|
|
|
|
#define MML_VERSION_OOT 0
|
|
#define MML_VERSION_MM 1
|
|
|
|
|
|
|
|
/**
|
|
* IO Ports
|
|
*/
|
|
|
|
#define IO_PORT_0 0
|
|
#define IO_PORT_1 1
|
|
#define IO_PORT_2 2
|
|
#define IO_PORT_3 3
|
|
#define IO_PORT_4 4
|
|
#define IO_PORT_5 5
|
|
#define IO_PORT_6 6
|
|
#define IO_PORT_7 7
|
|
|
|
|
|
|
|
/**
|
|
* Parameter Constants
|
|
*/
|
|
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
|
|
#define PITCH_A0 0
|
|
#define PITCH_BF0 1
|
|
#define PITCH_B0 2
|
|
#define PITCH_C1 3
|
|
#define PITCH_DF1 4
|
|
#define PITCH_D1 5
|
|
#define PITCH_EF1 6
|
|
#define PITCH_E1 7
|
|
#define PITCH_F1 8
|
|
#define PITCH_GF1 9
|
|
#define PITCH_G1 10
|
|
#define PITCH_AF1 11
|
|
#define PITCH_A1 12
|
|
#define PITCH_BF1 13
|
|
#define PITCH_B1 14
|
|
#define PITCH_C2 15
|
|
#define PITCH_DF2 16
|
|
#define PITCH_D2 17
|
|
#define PITCH_EF2 18
|
|
#define PITCH_E2 19
|
|
#define PITCH_F2 20
|
|
#define PITCH_GF2 21
|
|
#define PITCH_G2 22
|
|
#define PITCH_AF2 23
|
|
#define PITCH_A2 24
|
|
#define PITCH_BF2 25
|
|
#define PITCH_B2 26
|
|
#define PITCH_C3 27
|
|
#define PITCH_DF3 28
|
|
#define PITCH_D3 29
|
|
#define PITCH_EF3 30
|
|
#define PITCH_E3 31
|
|
#define PITCH_F3 32
|
|
#define PITCH_GF3 33
|
|
#define PITCH_G3 34
|
|
#define PITCH_AF3 35
|
|
#define PITCH_A3 36
|
|
#define PITCH_BF3 37
|
|
#define PITCH_B3 38
|
|
#define PITCH_C4 39
|
|
#define PITCH_DF4 40
|
|
#define PITCH_D4 41
|
|
#define PITCH_EF4 42
|
|
#define PITCH_E4 43
|
|
#define PITCH_F4 44
|
|
#define PITCH_GF4 45
|
|
#define PITCH_G4 46
|
|
#define PITCH_AF4 47
|
|
#define PITCH_A4 48
|
|
#define PITCH_BF4 49
|
|
#define PITCH_B4 50
|
|
#define PITCH_C5 51
|
|
#define PITCH_DF5 52
|
|
#define PITCH_D5 53
|
|
#define PITCH_EF5 54
|
|
#define PITCH_E5 55
|
|
#define PITCH_F5 56
|
|
#define PITCH_GF5 57
|
|
#define PITCH_G5 58
|
|
#define PITCH_AF5 59
|
|
#define PITCH_A5 60
|
|
#define PITCH_BF5 61
|
|
#define PITCH_B5 62
|
|
#define PITCH_C6 63
|
|
#define PITCH_DF6 64
|
|
#define PITCH_D6 65
|
|
#define PITCH_EF6 66
|
|
#define PITCH_E6 67
|
|
#define PITCH_F6 68
|
|
#define PITCH_GF6 69
|
|
#define PITCH_G6 70
|
|
#define PITCH_AF6 71
|
|
#define PITCH_A6 72
|
|
#define PITCH_BF6 73
|
|
#define PITCH_B6 74
|
|
#define PITCH_C7 75
|
|
#define PITCH_DF7 76
|
|
#define PITCH_D7 77
|
|
#define PITCH_EF7 78
|
|
#define PITCH_E7 79
|
|
#define PITCH_F7 80
|
|
#define PITCH_GF7 81
|
|
#define PITCH_G7 82
|
|
#define PITCH_AF7 83
|
|
#define PITCH_A7 84
|
|
#define PITCH_BF7 85
|
|
#define PITCH_B7 86
|
|
#define PITCH_C8 87
|
|
#define PITCH_DF8 88
|
|
#define PITCH_D8 89
|
|
#define PITCH_EF8 90
|
|
#define PITCH_E8 91
|
|
#define PITCH_F8 92
|
|
#define PITCH_GF8 93
|
|
#define PITCH_G8 94
|
|
#define PITCH_AF8 95
|
|
#define PITCH_A8 96
|
|
#define PITCH_BF8 97
|
|
#define PITCH_B8 98
|
|
#define PITCH_C9 99
|
|
#define PITCH_DF9 100
|
|
#define PITCH_D9 101
|
|
#define PITCH_EF9 102
|
|
#define PITCH_E9 103
|
|
#define PITCH_F9 104
|
|
#define PITCH_GF9 105
|
|
#define PITCH_G9 106
|
|
#define PITCH_AF9 107
|
|
#define PITCH_A9 108
|
|
#define PITCH_BF9 109
|
|
#define PITCH_B9 110
|
|
#define PITCH_C10 111
|
|
#define PITCH_DF10 112
|
|
#define PITCH_D10 113
|
|
#define PITCH_EF10 114
|
|
#define PITCH_E10 115
|
|
#define PITCH_F10 116
|
|
#define PITCH_BFNEG1 117
|
|
#define PITCH_BNEG1 118
|
|
#define PITCH_C0 119
|
|
#define PITCH_DF0 120
|
|
#define PITCH_D0 121
|
|
#define PITCH_EF0 122
|
|
#define PITCH_E0 123
|
|
#define PITCH_F0 124
|
|
#define PITCH_GF0 125
|
|
#define PITCH_G0 126
|
|
#define PITCH_AF0 127
|
|
|
|
// Hardcoded Instruments
|
|
#define FONTANY_INSTR_SFX 126
|
|
#define FONTANY_INSTR_DRUM 127
|
|
// Instruments implemented in gWaveSamples
|
|
#define FONTANY_INSTR_SAWTOOTH 128
|
|
#define FONTANY_INSTR_TRIANGLE 129
|
|
#define FONTANY_INSTR_SINE 130
|
|
#define FONTANY_INSTR_SQUARE 131
|
|
#define FONTANY_INSTR_NOISE 132
|
|
#define FONTANY_INSTR_BELL 133
|
|
#define FONTANY_INSTR_8PULSE 134
|
|
#define FONTANY_INSTR_4PULSE 135
|
|
#define FONTANY_INSTR_ASM_NOISE 136
|
|
|
|
|
|
/**
|
|
* Command Opcode IDs
|
|
*/
|
|
|
|
// control flow commands
|
|
#define ASEQ_OP_CONTROL_FLOW_FIRST 0xF2
|
|
#define ASEQ_OP_RBLTZ 0xF2
|
|
#define ASEQ_OP_RBEQZ 0xF3
|
|
#define ASEQ_OP_RJUMP 0xF4
|
|
#define ASEQ_OP_BGEZ 0xF5
|
|
#define ASEQ_OP_BREAK 0xF6
|
|
#define ASEQ_OP_LOOPEND 0xF7
|
|
#define ASEQ_OP_LOOP 0xF8
|
|
#define ASEQ_OP_BLTZ 0xF9
|
|
#define ASEQ_OP_BEQZ 0xFA
|
|
#define ASEQ_OP_JUMP 0xFB
|
|
#define ASEQ_OP_CALL 0xFC
|
|
#define ASEQ_OP_DELAY 0xFD
|
|
#define ASEQ_OP_DELAY1 0xFE
|
|
#define ASEQ_OP_END 0xFF
|
|
|
|
// sequence commands
|
|
#define ASEQ_OP_SEQ_TESTCHAN 0x00 // low nibble used as argument
|
|
#define ASEQ_OP_SEQ_STOPCHAN 0x40 // low nibble used as argument
|
|
#define ASEQ_OP_SEQ_SUBIO 0x50 // low nibble used as argument
|
|
#define ASEQ_OP_SEQ_LDRES 0x60 // low nibble used as argument
|
|
#define ASEQ_OP_SEQ_STIO 0x70 // low nibble used as argument
|
|
#define ASEQ_OP_SEQ_LDIO 0x80 // low nibble used as argument
|
|
#define ASEQ_OP_SEQ_LDCHAN 0x90 // low nibble used as argument
|
|
#define ASEQ_OP_SEQ_RLDCHAN 0xA0 // low nibble used as argument
|
|
#define ASEQ_OP_SEQ_LDSEQ 0xB0 // low nibble used as argument
|
|
#if (MML_VERSION == MML_VERSION_MM)
|
|
#define ASEQ_OP_SEQ_C2 0xC2
|
|
#define ASEQ_OP_SEQ_C3 0xC3
|
|
#endif
|
|
#define ASEQ_OP_SEQ_RUNSEQ 0xC4
|
|
#define ASEQ_OP_SEQ_SCRIPTCTR 0xC5
|
|
#define ASEQ_OP_SEQ_STOP 0xC6
|
|
#define ASEQ_OP_SEQ_STSEQ 0xC7
|
|
#define ASEQ_OP_SEQ_SUB 0xC8
|
|
#define ASEQ_OP_SEQ_AND 0xC9
|
|
#define ASEQ_OP_SEQ_LDI 0xCC
|
|
#define ASEQ_OP_SEQ_DYNCALL 0xCD
|
|
#define ASEQ_OP_SEQ_RAND 0xCE
|
|
#define ASEQ_OP_SEQ_NOTEALLOC 0xD0
|
|
#define ASEQ_OP_SEQ_LDSHORTGATEARR 0xD1
|
|
#define ASEQ_OP_SEQ_LDSHORTVELARR 0xD2
|
|
#define ASEQ_OP_SEQ_MUTEBHV 0xD3
|
|
#define ASEQ_OP_SEQ_MUTE 0xD4
|
|
#define ASEQ_OP_SEQ_MUTESCALE 0xD5
|
|
#define ASEQ_OP_SEQ_FREECHAN 0xD6
|
|
#define ASEQ_OP_SEQ_INITCHAN 0xD7
|
|
#define ASEQ_OP_SEQ_VOLSCALE 0xD9
|
|
#define ASEQ_OP_SEQ_VOLMODE 0xDA
|
|
#define ASEQ_OP_SEQ_VOL 0xDB
|
|
#define ASEQ_OP_SEQ_TEMPOCHG 0xDC
|
|
#define ASEQ_OP_SEQ_TEMPO 0xDD
|
|
#define ASEQ_OP_SEQ_RTRANSPOSE 0xDE
|
|
#define ASEQ_OP_SEQ_TRANSPOSE 0xDF
|
|
#define ASEQ_OP_SEQ_EF 0xEF
|
|
#define ASEQ_OP_SEQ_FREENOTELIST 0xF0
|
|
#define ASEQ_OP_SEQ_ALLOCNOTELIST 0xF1
|
|
|
|
// channel commands
|
|
#define ASEQ_OP_CHAN_CDELAY 0x00 // low nibble used as argument
|
|
#define ASEQ_OP_CHAN_LDSAMPLE 0x10 // low nibble used as argument
|
|
#define ASEQ_OP_CHAN_LDCHAN 0x20 // low nibble used as argument
|
|
#define ASEQ_OP_CHAN_STCIO 0x30 // low nibble used as argument
|
|
#define ASEQ_OP_CHAN_LDCIO 0x40 // low nibble used as argument
|
|
#define ASEQ_OP_CHAN_SUBIO 0x50 // low nibble used as argument
|
|
#define ASEQ_OP_CHAN_LDIO 0x60 // low nibble used as argument
|
|
#define ASEQ_OP_CHAN_STIO 0x70 // lower 3 bits used as argument
|
|
#define ASEQ_OP_CHAN_RLDLAYER 0x78 // lower 3 bits used as argument
|
|
#define ASEQ_OP_CHAN_TESTLAYER 0x80 // lower 3 bits used as argument
|
|
#define ASEQ_OP_CHAN_LDLAYER 0x88 // lower 3 bits used as argument
|
|
#define ASEQ_OP_CHAN_DELLAYER 0x90 // lower 3 bits used as argument
|
|
#define ASEQ_OP_CHAN_DYNLDLAYER 0x98 // lower 3 bits used as argument
|
|
#if (MML_VERSION == MML_VERSION_MM)
|
|
#define ASEQ_OP_CHAN_A0 0xA0
|
|
#define ASEQ_OP_CHAN_A1 0xA1
|
|
#define ASEQ_OP_CHAN_A2 0xA2
|
|
#define ASEQ_OP_CHAN_A3 0xA3
|
|
#define ASEQ_OP_CHAN_A4 0xA4
|
|
#define ASEQ_OP_CHAN_A5 0xA5
|
|
#define ASEQ_OP_CHAN_A6 0xA6
|
|
#define ASEQ_OP_CHAN_A7 0xA7
|
|
#define ASEQ_OP_CHAN_RANDPTR 0xA8
|
|
#endif
|
|
#define ASEQ_OP_CHAN_LDFILTER 0xB0
|
|
#define ASEQ_OP_CHAN_FREEFILTER 0xB1
|
|
#define ASEQ_OP_CHAN_LDSEQTOPTR 0xB2
|
|
#define ASEQ_OP_CHAN_FILTER 0xB3
|
|
#define ASEQ_OP_CHAN_PTRTODYNTBL 0xB4
|
|
#define ASEQ_OP_CHAN_DYNTBLTOPTR 0xB5
|
|
#define ASEQ_OP_CHAN_DYNTBLV 0xB6
|
|
#define ASEQ_OP_CHAN_RANDTOPTR 0xB7
|
|
#define ASEQ_OP_CHAN_RAND 0xB8
|
|
#define ASEQ_OP_CHAN_RANDVEL 0xB9
|
|
#define ASEQ_OP_CHAN_RANDGATE 0xBA
|
|
#define ASEQ_OP_CHAN_COMBFILTER 0xBB
|
|
#define ASEQ_OP_CHAN_PTRADD 0xBC
|
|
#if (MML_VERSION == MML_VERSION_OOT)
|
|
#define ASEQ_OP_CHAN_RANDPTR 0xBD
|
|
#endif
|
|
#if (MML_VERSION == MML_VERSION_MM)
|
|
#define ASEQ_OP_CHAN_SAMPLESTART 0xBD
|
|
#define ASEQ_OP_CHAN_UNK_BE 0xBE
|
|
#endif
|
|
#define ASEQ_OP_CHAN_INSTR 0xC1
|
|
#define ASEQ_OP_CHAN_DYNTBL 0xC2
|
|
#define ASEQ_OP_CHAN_SHORT 0xC3
|
|
#define ASEQ_OP_CHAN_NOSHORT 0xC4
|
|
#define ASEQ_OP_CHAN_DYNTBLLOOKUP 0xC5
|
|
#define ASEQ_OP_CHAN_FONT 0xC6
|
|
#define ASEQ_OP_CHAN_STSEQ 0xC7
|
|
#define ASEQ_OP_CHAN_SUB 0xC8
|
|
#define ASEQ_OP_CHAN_AND 0xC9
|
|
#define ASEQ_OP_CHAN_MUTEBHV 0xCA
|
|
#define ASEQ_OP_CHAN_LDSEQ 0xCB
|
|
#define ASEQ_OP_CHAN_LDI 0xCC
|
|
#define ASEQ_OP_CHAN_STOPCHAN 0xCD
|
|
#define ASEQ_OP_CHAN_LDPTR 0xCE
|
|
#define ASEQ_OP_CHAN_STPTRTOSEQ 0xCF
|
|
#define ASEQ_OP_CHAN_EFFECTS 0xD0
|
|
#define ASEQ_OP_CHAN_NOTEALLOC 0xD1
|
|
#define ASEQ_OP_CHAN_SUSTAIN 0xD2
|
|
#define ASEQ_OP_CHAN_BEND 0xD3
|
|
#define ASEQ_OP_CHAN_REVERB 0xD4
|
|
#define ASEQ_OP_CHAN_VIBFREQ 0xD7
|
|
#define ASEQ_OP_CHAN_VIBDEPTH 0xD8
|
|
#define ASEQ_OP_CHAN_RELEASERATE 0xD9
|
|
#define ASEQ_OP_CHAN_ENV 0xDA
|
|
#define ASEQ_OP_CHAN_TRANSPOSE 0xDB
|
|
#define ASEQ_OP_CHAN_PANWEIGHT 0xDC
|
|
#define ASEQ_OP_CHAN_PAN 0xDD
|
|
#define ASEQ_OP_CHAN_FREQSCALE 0xDE
|
|
#define ASEQ_OP_CHAN_VOL 0xDF
|
|
#define ASEQ_OP_CHAN_VOLEXP 0xE0
|
|
#define ASEQ_OP_CHAN_VIBFREQGRAD 0xE1
|
|
#define ASEQ_OP_CHAN_VIBDEPTHGRAD 0xE2
|
|
#define ASEQ_OP_CHAN_VIBDELAY 0xE3
|
|
#define ASEQ_OP_CHAN_DYNCALL 0xE4
|
|
#define ASEQ_OP_CHAN_REVERBIDX 0xE5
|
|
#define ASEQ_OP_CHAN_SAMPLEBOOK 0xE6
|
|
#define ASEQ_OP_CHAN_LDPARAMS 0xE7
|
|
#define ASEQ_OP_CHAN_PARAMS 0xE8
|
|
#define ASEQ_OP_CHAN_NOTEPRI 0xE9
|
|
#define ASEQ_OP_CHAN_STOP 0xEA
|
|
#define ASEQ_OP_CHAN_FONTINSTR 0xEB
|
|
#define ASEQ_OP_CHAN_VIBRESET 0xEC
|
|
#define ASEQ_OP_CHAN_GAIN 0xED
|
|
#define ASEQ_OP_CHAN_BENDFINE 0xEE
|
|
#define ASEQ_OP_CHAN_FREENOTELIST 0xF0
|
|
#define ASEQ_OP_CHAN_ALLOCNOTELIST 0xF1
|
|
|
|
// layer commands
|
|
#define ASEQ_OP_LAYER_NOTEDVG 0x00
|
|
#define ASEQ_OP_LAYER_NOTEDV 0x40
|
|
#define ASEQ_OP_LAYER_NOTEVG 0x80
|
|
#define ASEQ_OP_LAYER_LDELAY 0xC0
|
|
#define ASEQ_OP_LAYER_SHORTVEL 0xC1
|
|
#define ASEQ_OP_LAYER_TRANSPOSE 0xC2
|
|
#define ASEQ_OP_LAYER_SHORTDELAY 0xC3
|
|
#define ASEQ_OP_LAYER_LEGATO 0xC4
|
|
#define ASEQ_OP_LAYER_NOLEGATO 0xC5
|
|
#define ASEQ_OP_LAYER_INSTR 0xC6
|
|
#define ASEQ_OP_LAYER_PORTAMENTO 0xC7
|
|
#define ASEQ_OP_LAYER_NOPORTAMENTO 0xC8
|
|
#define ASEQ_OP_LAYER_SHORTGATE 0xC9
|
|
#define ASEQ_OP_LAYER_NOTEPAN 0xCA
|
|
#define ASEQ_OP_LAYER_ENV 0xCB
|
|
#define ASEQ_OP_LAYER_NODRUMPAN 0xCC
|
|
#define ASEQ_OP_LAYER_STEREO 0xCD
|
|
#define ASEQ_OP_LAYER_BENDFINE 0xCE
|
|
#define ASEQ_OP_LAYER_RELEASERATE 0xCF
|
|
#define ASEQ_OP_LAYER_LDSHORTVEL 0xD0 // low nibble used as an argument
|
|
#define ASEQ_OP_LAYER_LDSHORTGATE 0xE0 // low nibble used as an argument
|
|
#if (MML_VERSION == MML_VERSION_MM)
|
|
#define ASEQ_OP_LAYER_F0 0xF0
|
|
#define ASEQ_OP_LAYER_F1 0xF1
|
|
#endif
|
|
|
|
|
|
#ifdef _LANGUAGE_ASEQ
|
|
|
|
/**
|
|
* IDENT
|
|
*/
|
|
|
|
.ident "Zelda64 Audio Sequence compiled with GNU AS + aseq.h"
|
|
#if (MML_VERSION == MML_VERSION_OOT)
|
|
.ident "MML VERSION OOT"
|
|
#else
|
|
.ident "MML VERSION MM"
|
|
#endif
|
|
|
|
|
|
|
|
/**
|
|
* Sequence IDs
|
|
*/
|
|
|
|
// Some sequence instructions such as runseq would like sequence names for certain arguments.
|
|
// This facilitates making the sequence enum names available in sequence assembly files.
|
|
|
|
.set __SEQ_ID_CTR, 0
|
|
|
|
#define DEFINE_SEQUENCE(name, seqId, storageMedium, cachePolicy, seqFlags) \
|
|
.internal seqId; \
|
|
.set seqId, __SEQ_ID_CTR; \
|
|
.set __SEQ_ID_CTR, __SEQ_ID_CTR + 1
|
|
|
|
#define DEFINE_SEQUENCE_PTR(seqIdReal, seqId, storageMediumReal, cachePolicyReal, seqFlags) \
|
|
.internal seqId; \
|
|
.set seqId, __SEQ_ID_CTR; \
|
|
.set __SEQ_ID_CTR, __SEQ_ID_CTR + 1
|
|
|
|
#include "tables/sequence_table.h"
|
|
|
|
#undef DEFINE_SEQUENCE
|
|
#undef DEFINE_SEQUENCE_PTR
|
|
|
|
// Mark the counter as internal for the symbol table
|
|
.internal __SEQ_ID_CTR
|
|
|
|
|
|
|
|
/**
|
|
* STSEQ offsets
|
|
*/
|
|
|
|
#define STSEQ_HERE (. + 1)
|
|
|
|
// stores 1 byte (stseq)
|
|
#define STSEQ_LOOP_COUNT 1
|
|
#define STSEQ_VOL 1
|
|
#define STSEQ_PAN 1
|
|
#define STSEQ_REVERB 1
|
|
#define STSEQ_UNK_A4 1
|
|
#define STSEQ_FILTER_IDX 1
|
|
#define STSEQ_COMBFILTER_ARG1_HI 2
|
|
#define STSEQ_NOTEDV_OPCODE_PITCH 0
|
|
#define STSEQ_NOTEDV_DELAY 1
|
|
#define STSEQ_NOTEDV_DELAY_HI 1
|
|
#define STSEQ_NOTEDV_DELAY_LO 2
|
|
#define STSEQ_NOTEDV_VELOCITY 3
|
|
#define STSEQ_NOTEDV_VELOCITY_2 2
|
|
#define STSEQ_LDI_IMM 1
|
|
#define STSEQ_TRANSPOSITION 1
|
|
#define STSEQ_PORTAMENTO_MODE 1
|
|
#define STSEQ_PORTAMENTO_PITCH 2
|
|
#define STSEQ_PORTAMENTO_TIME 3
|
|
#define STSEQ_NOTEPAN 1
|
|
#define STSEQ_LDELAY 1
|
|
#define STSEQ_STSEQ_IMM 1
|
|
#define STSEQ_RAND 1
|
|
#define STSEQ_SURROUNDEFFECT 1
|
|
#define STSEQ_GENERAL_OPCODE 0
|
|
#define STSEQ_STEREO 1
|
|
#define STSEQ_BENDFINE 1
|
|
#define STSEQ_NOTEDVG_OPCODE_PITCH 0
|
|
#define STSEQ_NOTEDVG_DELAY_HI 1
|
|
#define STSEQ_NOTEDVG_DELAY_LO 2
|
|
#define STSEQ_NOTEDVG_VELOCITY_LONGDELAY 3
|
|
#define STSEQ_NOTEDVG_DELAY_SHORT 1
|
|
#define STSEQ_NOTEDVG_VELOCITY_SHORTDELAY 2
|
|
#define STSEQ_GAIN 1
|
|
#define STSEQ_INSTR 1
|
|
#define STSEQ_VIBDEPTH 1
|
|
#define STSEQ_SUB_IMM 1
|
|
#define STSEQ_INITCHAN_HI 1
|
|
#define STSEQ_INITCHAN_LO 2
|
|
#define STSEQ_VOLEXP 1
|
|
#define STSEQ_BEND 1
|
|
#define STSEQ_LDSEQ_SEQ_ID 1
|
|
|
|
// stores 2 bytes (stptrtoseq)
|
|
#define STSEQ_PTR_DYNTBL 1
|
|
#define STSEQ_PTR_LDLAYER 1
|
|
#define STSEQ_PTR_LDSEQ 1
|
|
#define STSEQ_PTR_STSEQ 2
|
|
|
|
// stores 2 bytes (so should be used with stptrtoseq)
|
|
#define STSEQ_ENVELOPE_POINT(n) (2 * (n))
|
|
|
|
|
|
|
|
/**
|
|
* Sequence Sections
|
|
*/
|
|
|
|
.internal ASEQ_MODE_NONE; .set ASEQ_MODE_NONE, 0
|
|
.internal ASEQ_MODE_SEQUENCE; .set ASEQ_MODE_SEQUENCE, 1
|
|
.internal ASEQ_MODE_CHANNEL; .set ASEQ_MODE_CHANNEL, 2
|
|
.internal ASEQ_MODE_LAYER; .set ASEQ_MODE_LAYER, 3
|
|
.internal ASEQ_MODE_TABLE; .set ASEQ_MODE_TABLE, 4
|
|
.internal ASEQ_MODE_ARRAY; .set ASEQ_MODE_ARRAY, 5
|
|
.internal ASEQ_MODE_FILTER; .set ASEQ_MODE_FILTER, 6
|
|
.internal ASEQ_MODE_ENVELOPE; .set ASEQ_MODE_ENVELOPE, 7
|
|
.internal ASEQ_MODE_BUFFER; .set ASEQ_MODE_BUFFER, 8
|
|
|
|
|
|
/* Macros that change structure based on current section */
|
|
.macro _RESET_SECTION
|
|
.purgem ldseq
|
|
.macro ldseq
|
|
.error "Invalid section for `ldseq`"
|
|
.endm
|
|
|
|
.purgem filter
|
|
.macro filter
|
|
.error "Invalid section for `filter`"
|
|
.endm
|
|
|
|
.purgem env
|
|
.macro env
|
|
.error "Invalid section for `env`"
|
|
.endm
|
|
.endm
|
|
|
|
/* Dummy macro definitions for above so purgem doesn't error on first run */
|
|
.macro ldseq
|
|
.endm
|
|
.macro filter
|
|
.endm
|
|
.macro env
|
|
.endm
|
|
|
|
/* Instantiate above macros */
|
|
_RESET_SECTION
|
|
|
|
/**
|
|
* Begin a sequence code section.
|
|
*/
|
|
.macro .sequence name
|
|
_RESET_SECTION
|
|
|
|
/* `ldseq` changes structure based on current section. */
|
|
.purgem ldseq
|
|
.macro ldseq ioPortNum, seqId, label
|
|
_wr_cmd_id ldseq, ASEQ_OP_SEQ_LDSEQ,,,,,,,, \ioPortNum, 4
|
|
_wr_u8 \seqId
|
|
_wr_lbl \label
|
|
.endm
|
|
|
|
.set ASEQ_MODE, ASEQ_MODE_SEQUENCE
|
|
\name:
|
|
.endm
|
|
|
|
/**
|
|
* Begin a channel code section.
|
|
*/
|
|
.macro .channel name
|
|
_RESET_SECTION
|
|
|
|
/* `ldseq` changes structure based on current section. */
|
|
.purgem ldseq
|
|
.macro ldseq label
|
|
_wr_cmd_id ldseq, ,ASEQ_OP_CHAN_LDSEQ,,,,,,, 0, 0
|
|
_wr_lbl \label
|
|
.endm
|
|
|
|
/* `filter` changes structure based on current section. */
|
|
.purgem filter
|
|
.macro filter lowpassCutoff, highpassCutoff
|
|
_check_arg_bitwidth_u \lowpassCutoff, 4
|
|
_check_arg_bitwidth_u \highpassCutoff, 4
|
|
|
|
_wr_cmd_id filter, ,ASEQ_OP_CHAN_FILTER,,,,,,, 0, 0
|
|
_wr_u8 (\lowpassCutoff << 4) | (\highpassCutoff)
|
|
.endm
|
|
|
|
/* `env` changes structure based on current section. */
|
|
.purgem env
|
|
.macro env label
|
|
_wr_cmd_id env, ,ASEQ_OP_CHAN_ENV,,,,,,, 0, 0
|
|
_wr_lbl \label
|
|
.endm
|
|
|
|
.set ASEQ_MODE, ASEQ_MODE_CHANNEL
|
|
\name:
|
|
.endm
|
|
|
|
/**
|
|
* Begin a layer code section.
|
|
*/
|
|
.macro .layer name
|
|
_RESET_SECTION
|
|
|
|
/* `env` changes structure based on current section. */
|
|
.purgem env
|
|
.macro env label, arg
|
|
_wr_cmd_id env, ,,ASEQ_OP_LAYER_ENV,,,,,, 0, 0
|
|
_wr_lbl \label
|
|
_wr_u8 \arg
|
|
.endm
|
|
|
|
.set ASEQ_MODE, ASEQ_MODE_LAYER
|
|
\name:
|
|
.endm
|
|
|
|
/**
|
|
* Begin a table section.
|
|
*/
|
|
.macro .table name
|
|
.balign 2
|
|
.table_unaligned \name
|
|
.endm
|
|
|
|
/**
|
|
* Begin a table section at an unaligned offset.
|
|
*/
|
|
.macro .table_unaligned name
|
|
_RESET_SECTION
|
|
|
|
.set ASEQ_MODE, ASEQ_MODE_TABLE
|
|
\name:
|
|
.endm
|
|
|
|
/**
|
|
* Begin an array section.
|
|
*/
|
|
.macro .array name
|
|
_RESET_SECTION
|
|
|
|
.set ASEQ_MODE, ASEQ_MODE_ARRAY
|
|
\name:
|
|
.endm
|
|
|
|
/**
|
|
* Begin a filter section.
|
|
*/
|
|
.macro .filter name
|
|
_RESET_SECTION
|
|
|
|
/* `filter` changes structure based on current section. */
|
|
.purgem filter
|
|
.macro filter a0, a1, a2, a3, a4, a5, a6, a7
|
|
_wr_s16 \a0
|
|
_wr_s16 \a1
|
|
_wr_s16 \a2
|
|
_wr_s16 \a3
|
|
_wr_s16 \a4
|
|
_wr_s16 \a5
|
|
_wr_s16 \a6
|
|
_wr_s16 \a7
|
|
.endm
|
|
|
|
.set ASEQ_MODE, ASEQ_MODE_FILTER
|
|
.balign 16
|
|
\name:
|
|
.endm
|
|
|
|
/**
|
|
* Begin an envelope section.
|
|
*/
|
|
.macro .envelope name
|
|
_RESET_SECTION
|
|
|
|
.set ASEQ_MODE, ASEQ_MODE_ENVELOPE
|
|
.balign 2
|
|
\name:
|
|
.endm
|
|
|
|
/**
|
|
* Begin a buffer section.
|
|
*/
|
|
.macro .buffer name
|
|
_RESET_SECTION
|
|
|
|
.set ASEQ_MODE, ASEQ_MODE_BUFFER
|
|
.balign 16
|
|
\name:
|
|
.endm
|
|
|
|
|
|
.macro _section_invalid macro_name
|
|
.if ASEQ_MODE == ASEQ_MODE_SEQUENCE
|
|
.error "Invalid section for `\macro_name`: Sequence"
|
|
.elseif ASEQ_MODE == ASEQ_MODE_CHANNEL
|
|
.error "Invalid section for `\macro_name`: Channel"
|
|
.elseif ASEQ_MODE == ASEQ_MODE_LAYER
|
|
.error "Invalid section for `\macro_name`: Layer"
|
|
.elseif ASEQ_MODE == ASEQ_MODE_TABLE
|
|
.error "Invalid section for `\macro_name`: Table"
|
|
.elseif ASEQ_MODE == ASEQ_MODE_ARRAY
|
|
.error "Invalid section for `\macro_name`: Array"
|
|
.elseif ASEQ_MODE == ASEQ_MODE_FILTER
|
|
.error "Invalid section for `\macro_name`: Filter"
|
|
.elseif ASEQ_MODE == ASEQ_MODE_ENVELOPE
|
|
.error "Invalid section for `\macro_name`: Envelope"
|
|
.elseif ASEQ_MODE == ASEQ_MODE_BUFFER
|
|
.error "Invalid section for `\macro_name`: Buffer"
|
|
.else
|
|
.error "Invalid section"
|
|
.endif
|
|
.endm
|
|
|
|
|
|
|
|
/**
|
|
* Sequence Start/End
|
|
*/
|
|
|
|
.macro .startseq name
|
|
/* Begin a sequence. */
|
|
|
|
/* Write the sequence name into a special .note.name section */
|
|
.pushsection .note.name, "", @note
|
|
.asciz "\name"
|
|
.popsection
|
|
|
|
/* Reset section and write start symbol. */
|
|
.section .data, "wa", @progbits
|
|
.set ASEQ_MODE, ASEQ_MODE_NONE
|
|
.balign 16
|
|
.global \name\()_Start
|
|
\name\()_Start:
|
|
_seq_start:
|
|
.endm
|
|
|
|
.macro .endseq name
|
|
/* End a sequence. Align to 16 bytes, write end and size symbols. */
|
|
.balign 16
|
|
_seq_end:
|
|
.global \name\()_End
|
|
\name\()_End:
|
|
.global \name\()_Size
|
|
.set \name\()_Size, _seq_end - _seq_start
|
|
/* Mark ASEQ_MODE as an internal symbol at the very end since it is redefined many times */
|
|
.internal ASEQ_MODE
|
|
.endm
|
|
|
|
|
|
|
|
/**
|
|
* Parameters
|
|
*/
|
|
|
|
.macro _check_arg_bitwidth_u value, num
|
|
/* Checks if the unsigned integer `value` fits within `num` bits. */
|
|
.if (\value & ((1 << \num) - 1)) != \value
|
|
.error "value \value out of range for unsigned \num\()-bit argument"
|
|
.endif
|
|
.endm
|
|
|
|
.macro _check_arg_bitwidth_s value, num
|
|
/* Checks if the signed integer `value` fits within `num` bits. */
|
|
.if (\value & ((1 << (\num - 1)) - 1)) - (\value & (1 << (\num - 1))) != \value
|
|
.error "value \value out of range for signed \num\()-bit argument"
|
|
.endif
|
|
.endm
|
|
|
|
/* Long encoded numbers a la MIDI */
|
|
.macro _var_long x
|
|
_check_arg_bitwidth_u \x, 15
|
|
|
|
.byte (0x80 | (\x & 0x7f00) >> 8), (\x & 0xff)
|
|
.endm
|
|
|
|
/* Potentially long encoded numbers, but may not be. */
|
|
.macro _var x
|
|
.if (\x >= 0x80)
|
|
_var_long \x
|
|
.else
|
|
_check_arg_bitwidth_u \x, 8
|
|
.byte \x
|
|
.endif
|
|
.endm
|
|
|
|
.macro _wr8 value
|
|
/* Write 8 bits */
|
|
.byte (\value) & 0xFF
|
|
.endm
|
|
|
|
.macro _wr16 value
|
|
/* Write 16 bits (big-endian) */
|
|
.byte (\value) >> 8, (\value) & 0xFF
|
|
.endm
|
|
|
|
.macro _wr_s8 value
|
|
/* Ensure the provided arg value fits in 8 bits (signed) */
|
|
_check_arg_bitwidth_s \value, 8
|
|
_wr8 \value
|
|
.endm
|
|
|
|
.macro _wr_u8 value
|
|
/* Ensure the provided arg value fits in 8 bits (unsigned) */
|
|
_check_arg_bitwidth_u \value, 8
|
|
_wr8 \value
|
|
.endm
|
|
|
|
.macro _wr_s16 value
|
|
/* Ensure the provided arg value fits in 16 bits (signed) */
|
|
_check_arg_bitwidth_s \value, 16
|
|
_wr16 \value
|
|
.endm
|
|
|
|
.macro _wr_u16 value
|
|
/* Ensure the provided arg value fits in 16 bits (unsigned) */
|
|
_check_arg_bitwidth_u \value, 16
|
|
_wr16 \value
|
|
.endm
|
|
|
|
.macro _wr_lbl value
|
|
/* Subtract sequence start label to get a numeric offset that can be written at assembling time */
|
|
_wr16 (\value - _seq_start)
|
|
.endm
|
|
|
|
.macro _wr_16_rel value
|
|
/* Turn label into relative offset.
|
|
* Can't check encoding, complains about non-constant value.. */
|
|
_wr16 (\value - $reladdr\@)
|
|
$reladdr\@:
|
|
.endm
|
|
|
|
.macro _wr_8_rel value
|
|
/* Turn label into relative offset.
|
|
* Can't check encoding, complains about non-constant value.. */
|
|
_wr8 (\value - $reladdr\@)
|
|
$reladdr\@:
|
|
.endm
|
|
|
|
.macro _wr_cmd_id cmd_name, seq_id=-1, chan_id=-1, layer_id=-1, tbl_id=-1, arr_id=-1, filt_id=-1, env_id=-1, buf_id=-1, lo_bits, n_lo_bits
|
|
/* Helper for writing command ids. Will write the command id appropriate for the current section, optionally
|
|
* packing in low-order bits if a command uses them for an argument. */
|
|
_check_arg_bitwidth_u \lo_bits, \n_lo_bits
|
|
|
|
.if ASEQ_MODE == ASEQ_MODE_SEQUENCE && \seq_id != -1
|
|
_check_arg_bitwidth_u \seq_id, 8
|
|
.byte (\seq_id & 0xFF) | (\lo_bits)
|
|
.elseif ASEQ_MODE == ASEQ_MODE_CHANNEL && \chan_id != -1
|
|
_check_arg_bitwidth_u \chan_id, 8
|
|
.byte (\chan_id & 0xFF) | (\lo_bits)
|
|
.elseif ASEQ_MODE == ASEQ_MODE_LAYER && \layer_id != -1
|
|
_check_arg_bitwidth_u \layer_id, 8
|
|
.byte (\layer_id & 0xFF) | (\lo_bits)
|
|
.elseif ASEQ_MODE == ASEQ_MODE_TABLE && \tbl_id != -1
|
|
_check_arg_bitwidth_u \tbl_id, 8
|
|
.byte (\tbl_id & 0xFF) | (\lo_bits)
|
|
.elseif ASEQ_MODE == ASEQ_MODE_ARRAY && \arr_id != -1
|
|
_check_arg_bitwidth_u \arr_id, 8
|
|
.byte (\arr_id & 0xFF) | (\lo_bits)
|
|
.elseif ASEQ_MODE == ASEQ_MODE_FILTER && \filt_id != -1
|
|
_check_arg_bitwidth_u \filt_id, 8
|
|
.byte (\filt_id & 0xFF) | (\lo_bits)
|
|
.elseif ASEQ_MODE == ASEQ_MODE_ENVELOPE && \env_id != -1
|
|
_check_arg_bitwidth_u \env_id, 8
|
|
.byte (\env_id & 0xFF) | (\lo_bits)
|
|
.elseif ASEQ_MODE == ASEQ_MODE_BUFFER && \buf_id != -1
|
|
_check_arg_bitwidth_u \buf_id, 8
|
|
.byte (\buf_id & 0xFF) | (\lo_bits)
|
|
.else
|
|
_section_invalid \cmd_name
|
|
.endif
|
|
.endm
|
|
|
|
.macro .ptr value
|
|
_wr_lbl \value
|
|
.endm
|
|
|
|
.macro .ptr_raw value
|
|
_wr16 \value
|
|
.endm
|
|
|
|
|
|
|
|
/**
|
|
* Instructions
|
|
*/
|
|
|
|
/**
|
|
* end
|
|
*
|
|
* Marks the end of an executable section.
|
|
*
|
|
* If CALLDEPTH is not 0 (that is, execution is currently in a subroutine)
|
|
* the current subroutine is exited and execution continues at the saved
|
|
* return address. If CALLDEPTH is 0, the current layer/channel/sequence is
|
|
* closed. If the sequence is closed, all execution ends. If a channel is
|
|
* closed, so are its layers.
|
|
*/
|
|
.macro end
|
|
_wr_cmd_id end, ASEQ_OP_END,ASEQ_OP_END,ASEQ_OP_END,,,,,, 0, 0
|
|
.endm
|
|
|
|
/**
|
|
* delay1
|
|
*
|
|
* Delays for one tick.
|
|
*/
|
|
.macro delay1
|
|
_wr_cmd_id delay1, ASEQ_OP_DELAY1,ASEQ_OP_DELAY1,,,,,,, 0, 0
|
|
.endm
|
|
|
|
/**
|
|
* delay <delay:var>
|
|
*
|
|
* Delays for `delay` ticks.
|
|
*/
|
|
.macro delay delay
|
|
_wr_cmd_id delay, ASEQ_OP_DELAY,ASEQ_OP_DELAY,,,,,,, 0, 0
|
|
_var \delay
|
|
.endm
|
|
|
|
/**
|
|
* call <label:lbl>
|
|
*
|
|
* Unconditionally enters a subroutine at `label`. Execution will resume following this instruction once the
|
|
* subroutine encounters an `end` instruction.
|
|
*/
|
|
.macro call label
|
|
_wr_cmd_id call, ASEQ_OP_CALL,ASEQ_OP_CALL,ASEQ_OP_CALL,,,,,, 0, 0
|
|
_wr_lbl \label
|
|
.endm
|
|
|
|
/**
|
|
* jump <label:lbl>
|
|
*
|
|
* Branches to `label` unconditionally.
|
|
*/
|
|
.macro jump label
|
|
_wr_cmd_id jump, ASEQ_OP_JUMP,ASEQ_OP_JUMP,ASEQ_OP_JUMP,,,,,, 0, 0
|
|
_wr_lbl \label
|
|
.endm
|
|
|
|
/**
|
|
* beqz <label:lbl>
|
|
*
|
|
* Branches to `label` if TR == 0.
|
|
*/
|
|
.macro beqz label
|
|
_wr_cmd_id beqz, ASEQ_OP_BEQZ,ASEQ_OP_BEQZ,ASEQ_OP_BEQZ,,,,,, 0, 0
|
|
_wr_lbl \label
|
|
.endm
|
|
|
|
/**
|
|
* bltz <label:lbl>
|
|
*
|
|
* Branches to `label` if TR < 0.
|
|
*/
|
|
.macro bltz label
|
|
_wr_cmd_id beqz, ASEQ_OP_BLTZ,ASEQ_OP_BLTZ,ASEQ_OP_BLTZ,,,,,, 0, 0
|
|
_wr_lbl \label
|
|
.endm
|
|
|
|
/**
|
|
* loop <num:u8>
|
|
*
|
|
* Begin a loop for `num` iterations, pushing the address of the next
|
|
* instruction to the call stack.
|
|
*
|
|
* Maximum loop nesting level is 4 - CALLDEPTH, after this the call stack
|
|
* becomes full.
|
|
*/
|
|
.macro loop num
|
|
_wr_cmd_id loop, ASEQ_OP_LOOP,ASEQ_OP_LOOP,ASEQ_OP_LOOP,,,,,, 0, 0
|
|
_wr_u8 \num
|
|
.endm
|
|
|
|
/**
|
|
* loopend
|
|
*
|
|
* Indicates the end of a loop body. Whenever the instruction is executed
|
|
* the loop counter decrements and either branches back to the loop start
|
|
* if there are remaining iterations or exits the loop if all iterations
|
|
* have been completed. When the loop is to be exited, the top of the call
|
|
* stack is popped.
|
|
*/
|
|
.macro loopend
|
|
_wr_cmd_id loopend, ASEQ_OP_LOOPEND,ASEQ_OP_LOOPEND,ASEQ_OP_LOOPEND,,,,,, 0, 0
|
|
.endm
|
|
|
|
/**
|
|
* break
|
|
*
|
|
* Immediately ends the current loop, popping it from the call stack, but
|
|
* does not branch to the end of the loop.
|
|
*
|
|
* Programming Note: Do not allow execution to later flow into loopend, as
|
|
* the call stack would be popped twice.
|
|
*/
|
|
.macro break
|
|
_wr_cmd_id break, ASEQ_OP_BREAK,ASEQ_OP_BREAK,ASEQ_OP_BREAK,,,,,, 0, 0
|
|
.endm
|
|
|
|
/**
|
|
* bgez <label:lbl>
|
|
*
|
|
* Branches to `label` if TR >= 0.
|
|
*/
|
|
.macro bgez label
|
|
_wr_cmd_id bgez, ASEQ_OP_BGEZ,ASEQ_OP_BGEZ,ASEQ_OP_BGEZ,,,,,, 0, 0
|
|
_wr_lbl \label
|
|
.endm
|
|
|
|
/**
|
|
* rjump <label:lbl>
|
|
*
|
|
* Branches to `label` unconditionally.
|
|
* `label` is a relative offset rather than an absolute offset, making it appropriate
|
|
* for use in position-independent code.
|
|
* Note that the range is reduced compared to absolute jumps, only labels within a
|
|
* signed 8-bit (+/-128) range are reachable.
|
|
*/
|
|
.macro rjump label
|
|
_wr_cmd_id rjump, ASEQ_OP_RJUMP,ASEQ_OP_RJUMP,ASEQ_OP_RJUMP,,,,,, 0, 0
|
|
_wr_8_rel \label
|
|
.endm
|
|
|
|
/**
|
|
* rbeqz <label:lbl>
|
|
*
|
|
* Branches to `label` if TR == 0.
|
|
* `label` is a relative offset rather than an absolute offset, making it appropriate
|
|
* for use in position-independent code.
|
|
* Note that the range is reduced compared to absolute branches, only labels within a
|
|
* signed 8-bit (+/-128) range are reachable.
|
|
*/
|
|
.macro rbeqz label
|
|
_wr_cmd_id rbeqz, ASEQ_OP_RBEQZ,ASEQ_OP_RBEQZ,ASEQ_OP_RBEQZ,,,,,, 0, 0
|
|
_wr_8_rel \label
|
|
.endm
|
|
|
|
/**
|
|
* rbltz <label:lbl>
|
|
*
|
|
* Branches to `label` if TR < 0.
|
|
* `label` is a relative offset rather than an absolute offset, making it appropriate
|
|
* for use in position-independent code.
|
|
* Note that the range is reduced compared to absolute branches, only labels within a
|
|
* signed 8-bit (+/-128) range are reachable.
|
|
*/
|
|
.macro rbltz label
|
|
_wr_cmd_id rbltz, ASEQ_OP_RBLTZ,ASEQ_OP_RBLTZ,ASEQ_OP_RBLTZ,,,,,, 0, 0
|
|
_wr_8_rel \label
|
|
.endm
|
|
|
|
/**
|
|
* allocnotelist <num:u8>
|
|
*
|
|
* Clears the channel note pool and reallocates it with space for `num` notes.
|
|
*/
|
|
.macro allocnotelist num
|
|
_wr_cmd_id allocnotelist, ASEQ_OP_SEQ_ALLOCNOTELIST,ASEQ_OP_CHAN_ALLOCNOTELIST,,,,,,, 0, 0
|
|
_wr_u8 \num
|
|
.endm
|
|
|
|
/**
|
|
* freenotelist
|
|
*
|
|
* Clears the channel note pool.
|
|
*/
|
|
.macro freenotelist
|
|
_wr_cmd_id freenotelist, ASEQ_OP_SEQ_FREENOTELIST,ASEQ_OP_CHAN_FREENOTELIST,,,,,,, 0, 0
|
|
.endm
|
|
|
|
/**
|
|
* unk_EF
|
|
*
|
|
* Has no function.
|
|
*/
|
|
.macro unk_EF arg1, arg2
|
|
_wr_cmd_id unk_EF, ASEQ_OP_SEQ_EF,,,,,,,, 0, 0
|
|
_wr_s16 \arg1
|
|
_w_u8 \arg2
|
|
.endm
|
|
|
|
/**
|
|
* bendfine <amt:s8>
|
|
*
|
|
* Fine-tunes the pitch bend amount for the channel or layer.
|
|
*/
|
|
.macro bendfine amt
|
|
_wr_cmd_id bendfine, ,ASEQ_OP_CHAN_BENDFINE,ASEQ_OP_LAYER_BENDFINE,,,,,, 0, 0
|
|
_wr_s8 \amt
|
|
.endm
|
|
|
|
/**
|
|
* gain <value:u8>
|
|
*
|
|
* Sets the channel gain (multiplicative volume scale factor) to the provided qu4.4 fixed-point value.
|
|
*/
|
|
.macro gain value
|
|
_wr_cmd_id gain, ,ASEQ_OP_CHAN_GAIN,,,,,,, 0, 0
|
|
_wr_u8 \value
|
|
.endm
|
|
|
|
/**
|
|
* vibreset
|
|
*
|
|
* Resets channel vibrato, filter, gain, sustain, etc. state.
|
|
*/
|
|
.macro vibreset
|
|
_wr_cmd_id vibreset, ,ASEQ_OP_CHAN_VIBRESET,,,,,,, 0, 0
|
|
.endm
|
|
|
|
/**
|
|
* fontinstr <fontId:u8> <instId:u8>
|
|
*
|
|
* Updates the soundfont and instrument for the channel simultaneously.
|
|
*/
|
|
.macro fontinstr fontId, instId
|
|
_wr_cmd_id fontinstr, ,ASEQ_OP_CHAN_FONTINSTR,,,,,,, 0, 0
|
|
_wr_u8 \fontId
|
|
_wr_u8 \instId
|
|
.endm
|
|
|
|
/**
|
|
* notepri <priority1:u4> <priority2:u4>
|
|
*
|
|
* Set note priorities.
|
|
*/
|
|
.macro notepri priority1, priority2
|
|
_check_arg_bitwidth_u \priority1, 4
|
|
_check_arg_bitwidth_u \priority2, 4
|
|
_wr_cmd_id notepri, ,ASEQ_OP_CHAN_NOTEPRI,,,,,,, 0, 0
|
|
_wr_u8 (\priority1 << 4) | \priority2
|
|
.endm
|
|
|
|
/**
|
|
* params <muteBhv:u8> <noteAllocPolicy:u8> <channelPriority:u8> <transposition:u8>
|
|
* <pan:u8> <panWeight:u8> <reverb:u8> <reverbIndex:u8>
|
|
*
|
|
* Sets various channel parameters.
|
|
*/
|
|
.macro params muteBhv, noteAllocPolicy, channelPriority, transposition, pan, panWeight, reverb, reverbIndex
|
|
_wr_cmd_id params, ,ASEQ_OP_CHAN_PARAMS,,,,,,, 0, 0
|
|
_wr_u8 \muteBhv
|
|
_wr_u8 \noteAllocPolicy
|
|
_wr_u8 \channelPriority
|
|
_wr_u8 \transposition
|
|
_wr_u8 \pan
|
|
_wr_u8 \panWeight
|
|
_wr_u8 \reverb
|
|
_wr_u8 \reverbIndex
|
|
.endm
|
|
|
|
/**
|
|
* ldparams <label:lbl>
|
|
*
|
|
* Sets various channel parameters by loading them from `label`. The data
|
|
* is ordered in the same way as the arguments in `params`.
|
|
*/
|
|
.macro ldparams label
|
|
_wr_cmd_id ldparams, ,ASEQ_OP_CHAN_LDPARAMS,,,,,,, 0, 0
|
|
_wr_lbl \label
|
|
.endm
|
|
|
|
/**
|
|
* samplebook <value:u8>
|
|
*
|
|
* Sets the sample book mode.
|
|
*/
|
|
.macro samplebook value
|
|
_wr_cmd_id samplebook, ,ASEQ_OP_CHAN_SAMPLEBOOK,,,,,,, 0, 0
|
|
_wr_u8 \value
|
|
.endm
|
|
|
|
/**
|
|
* reverbidx <arg:u8>
|
|
*
|
|
* Sets the channel reverb.
|
|
*/
|
|
.macro reverbidx arg
|
|
_wr_cmd_id reverbidx, ,ASEQ_OP_CHAN_REVERBIDX,,,,,,, 0, 0
|
|
_wr_u8 \arg
|
|
.endm
|
|
|
|
/**
|
|
* reverbidx <arg:u8>
|
|
*
|
|
* Sets the channel vibrato delay.
|
|
*/
|
|
.macro vibdelay arg
|
|
_wr_cmd_id vibdelay, ,ASEQ_OP_CHAN_VIBDELAY,,,,,,, 0, 0
|
|
_wr_u8 \arg
|
|
.endm
|
|
|
|
/**
|
|
* vibdepthgrad <extentStart:u8> <extentTarget:u8> <extentChangeDelay:u8>
|
|
*
|
|
* Sets the vibrato extent.
|
|
*/
|
|
.macro vibdepthgrad arg0, arg1, arg2
|
|
_wr_cmd_id vibdepthgrad, ,ASEQ_OP_CHAN_VIBDEPTHGRAD,,,,,,, 0, 0
|
|
_wr_u8 \arg0
|
|
_wr_u8 \arg1
|
|
_wr_u8 \arg2
|
|
.endm
|
|
|
|
/**
|
|
* vibfreqgrad <rateStart:u8> <rateTarget:u8> <rateChangeDelay:u8>
|
|
*
|
|
* Sets the vibrato rate.
|
|
*/
|
|
.macro vibfreqgrad arg0, arg1, arg2
|
|
_wr_cmd_id vibfreqgrad, ,ASEQ_OP_CHAN_VIBFREQGRAD,,,,,,, 0, 0
|
|
_wr_u8 \arg0
|
|
_wr_u8 \arg1
|
|
_wr_u8 \arg2
|
|
.endm
|
|
|
|
/**
|
|
* volexp <amt:u8>
|
|
*
|
|
* Changes the expression amount for the channel.
|
|
*/
|
|
.macro volexp amt
|
|
_wr_cmd_id volexp, ,ASEQ_OP_CHAN_VOLEXP,,,,,,, 0, 0
|
|
_wr_u8 \amt
|
|
.endm
|
|
|
|
/**
|
|
* transpose <semitones:s8>
|
|
*
|
|
* Sets the transposition amount. Transposition shifts all note pitches by the
|
|
* provided number of semitones.
|
|
*/
|
|
.macro transpose semitones
|
|
_wr_cmd_id transpose, ASEQ_OP_SEQ_TRANSPOSE,ASEQ_OP_CHAN_TRANSPOSE,ASEQ_OP_LAYER_TRANSPOSE,,,,,, 0, 0
|
|
_wr_s8 \semitones
|
|
.endm
|
|
|
|
/**
|
|
* rtranspose <semitones:s8>
|
|
*
|
|
* Adjusts the transposition amount. This is only available at the top sequence level.
|
|
*/
|
|
.macro rtranspose semitones
|
|
_wr_cmd_id rtranspose, ASEQ_OP_SEQ_RTRANSPOSE,,,,,,,, 0, 0
|
|
_wr_s8 \semitones
|
|
.endm
|
|
|
|
/**
|
|
* freqscale <arg:s16>
|
|
*
|
|
* Sets the freqScale for the current channel.
|
|
*/
|
|
.macro freqscale arg
|
|
_wr_cmd_id freqscale, ,ASEQ_OP_CHAN_FREQSCALE,,,,,,, 0, 0
|
|
_wr_s16 \arg
|
|
.endm
|
|
|
|
/**
|
|
* tempo <bpm:u8>
|
|
*
|
|
* Changes the tempo of the sequence.
|
|
*/
|
|
.macro tempo bpm
|
|
_wr_cmd_id tempo, ASEQ_OP_SEQ_TEMPO,,,,,,,, 0, 0
|
|
_wr_u8 \bpm
|
|
.endm
|
|
|
|
/**
|
|
* tempochg <arg:s8>
|
|
*
|
|
* Sets the tempoChange for the sequence.
|
|
*/
|
|
.macro tempochg arg
|
|
_wr_cmd_id tempochg, ASEQ_OP_SEQ_TEMPOCHG,,,,,,,, 0, 0
|
|
_wr_s8 \arg
|
|
.endm
|
|
|
|
/**
|
|
* pan <amt:u8>
|
|
*
|
|
* Changes the pan amount for a channel.
|
|
*/
|
|
.macro pan pan
|
|
/* pan can only take values in 0..127 */
|
|
_check_arg_bitwidth_u \pan, 7
|
|
_wr_cmd_id pan, ,ASEQ_OP_CHAN_PAN,,,,,,, 0, 0
|
|
_wr_u8 \pan
|
|
.endm
|
|
|
|
/**
|
|
* panweight <weight:u8>
|
|
*
|
|
* Controls how much the final pan value is influenced by the channel pan and layer pan.
|
|
* The layer pan is set by the drum instrument pan.
|
|
* A value of 0 ignores channel pan, while a value of 127 ignores layer pan.
|
|
*
|
|
* finalPan = (weight * channelPan + (128 - weight) * layerPan) / 128
|
|
*/
|
|
.macro panweight weight
|
|
/* weight can only take values in 0..127 */
|
|
_check_arg_bitwidth_u \weight, 7
|
|
_wr_cmd_id panweight, ,ASEQ_OP_CHAN_PANWEIGHT,,,,,,, 0, 0
|
|
_wr_u8 \weight
|
|
.endm
|
|
|
|
/**
|
|
* vol <amt:u8>
|
|
*
|
|
* Sets the volume amount for this sequence or channel.
|
|
*/
|
|
.macro vol amt
|
|
_wr_cmd_id vol, ASEQ_OP_SEQ_VOL,ASEQ_OP_CHAN_VOL,,,,,,, 0, 0
|
|
_wr_u8 \amt
|
|
.endm
|
|
|
|
/**
|
|
* volmode <mode:u8> <fadeTimer:s16>
|
|
*
|
|
* TODO DESCRIPTION
|
|
*/
|
|
.macro volmode mode, fadeTimer
|
|
_wr_cmd_id volmode, ASEQ_OP_SEQ_VOLMODE,,,,,,,, 0, 0
|
|
_wr_u8 \mode
|
|
_wr_u16 \fadeTimer
|
|
.endm
|
|
|
|
/**
|
|
* volscale <arg:u8>
|
|
*
|
|
* Sets the fadeVolumeScale for the sequence.
|
|
*/
|
|
.macro volscale arg
|
|
_wr_cmd_id volscale, ASEQ_OP_SEQ_VOLSCALE,,,,,,,, 0, 0
|
|
_wr_u8 \arg
|
|
.endm
|
|
|
|
/**
|
|
* releaserate <release:u8>
|
|
*
|
|
* Sets the envelope release rate for this channel or layer.
|
|
*/
|
|
.macro releaserate release
|
|
_wr_cmd_id releaserate, ,ASEQ_OP_CHAN_RELEASERATE,ASEQ_OP_LAYER_RELEASERATE,,,,,, 0, 0
|
|
_wr_u8 \release
|
|
.endm
|
|
|
|
/**
|
|
* vibdepth <arg:u8>
|
|
*
|
|
* Sets the vibrato depth for the channel.
|
|
*/
|
|
.macro vibdepth arg
|
|
_wr_cmd_id vibdepth, ,ASEQ_OP_CHAN_VIBDEPTH,,,,,,, 0, 0
|
|
_wr_u8 \arg
|
|
.endm
|
|
|
|
/**
|
|
* vibfreq <arg:u8>
|
|
*
|
|
* Sets the vibrato rate for the channel.
|
|
*/
|
|
.macro vibfreq arg
|
|
_wr_cmd_id vibfreq, ,ASEQ_OP_CHAN_VIBFREQ,,,,,,, 0, 0
|
|
_wr_u8 \arg
|
|
.endm
|
|
|
|
/**
|
|
* initchan <bitmask:u16>
|
|
*
|
|
* Initializes the channels marked in the provided bitmask.
|
|
*
|
|
* e.g. initchan 0b1 initializes channel 0.
|
|
* initchan 0b101 initializes channels 0 and 2.
|
|
*/
|
|
.macro initchan bitmask
|
|
_wr_cmd_id initchan, ASEQ_OP_SEQ_INITCHAN,,,,,,,, 0, 0
|
|
_wr_u16 \bitmask
|
|
.endm
|
|
|
|
/**
|
|
* freechan <bitmask:u16>
|
|
*
|
|
* Frees the channels marked in the provided bitmask.
|
|
*/
|
|
.macro freechan bitmask
|
|
_wr_cmd_id freechan, ASEQ_OP_SEQ_FREECHAN,,,,,,,, 0, 0
|
|
_wr_u16 \bitmask
|
|
.endm
|
|
|
|
/**
|
|
* mutescale <arg:s8>
|
|
*
|
|
* Sets the muteVolumeScale for the sequence.
|
|
*/
|
|
.macro mutescale arg
|
|
_wr_cmd_id mutescale, ASEQ_OP_SEQ_MUTESCALE,,,,,,,, 0, 0
|
|
_wr_s8 \arg
|
|
.endm
|
|
|
|
/**
|
|
* mute
|
|
*
|
|
* Mutes the sequence player.
|
|
*/
|
|
.macro mute
|
|
_wr_cmd_id mute, ASEQ_OP_SEQ_MUTE,,,,,,,, 0, 0
|
|
.endm
|
|
|
|
/**
|
|
* reverb <amt:u8>
|
|
*
|
|
* Sets the reverb amount for this channel.
|
|
*/
|
|
.macro reverb amt
|
|
_wr_cmd_id reverb, ,ASEQ_OP_CHAN_REVERB,,,,,,, 0, 0
|
|
_wr_u8 \amt
|
|
.endm
|
|
|
|
/**
|
|
* mutebhv <flags:u8>
|
|
*
|
|
* Sets mute behavior for this sequence or channel.
|
|
*/
|
|
.macro mutebhv flags
|
|
_wr_cmd_id mutebhv, ASEQ_OP_SEQ_MUTEBHV,ASEQ_OP_CHAN_MUTEBHV,,,,,,, 0, 0
|
|
_wr_u8 \flags
|
|
.endm
|
|
|
|
/**
|
|
* bend <amt:s8>
|
|
*
|
|
* Sets the pitch bend amount for this channel.
|
|
*/
|
|
.macro bend amt
|
|
_wr_cmd_id bend, ,ASEQ_OP_CHAN_BEND,,,,,,, 0, 0
|
|
_wr_s8 \amt
|
|
.endm
|
|
|
|
/**
|
|
* ldshortvelarr <label:lbl>
|
|
*
|
|
* Sets the location of SHORTVELTBL.
|
|
*/
|
|
.macro ldshortvelarr label
|
|
_wr_cmd_id ldshortvelarr, ASEQ_OP_SEQ_LDSHORTVELARR,,,,,,,, 0, 0
|
|
_wr_lbl \label
|
|
.endm
|
|
|
|
/**
|
|
* sustain <value:u8>
|
|
*
|
|
* Sets the adsr sustain value for this channel.
|
|
*/
|
|
.macro sustain value
|
|
_wr_cmd_id sustain, ,ASEQ_OP_CHAN_SUSTAIN,,,,,,, 0, 0
|
|
_wr_u8 \value
|
|
.endm
|
|
|
|
/**
|
|
* ldshortgatearr <label:lbl>
|
|
*
|
|
* Sets the location of SHORTGATETBL.
|
|
*/
|
|
.macro ldshortgatearr label
|
|
_wr_cmd_id ldshortgatearr, ASEQ_OP_SEQ_LDSHORTGATEARR,,,,,,,, 0, 0
|
|
_wr_lbl \label
|
|
.endm
|
|
|
|
/**
|
|
* notealloc <arg:u8>
|
|
*
|
|
* Sets the noteAllocPolicy for either the sequence or the current channel.
|
|
*/
|
|
.macro notealloc arg
|
|
_wr_cmd_id notealloc, ASEQ_OP_SEQ_NOTEALLOC,ASEQ_OP_CHAN_NOTEALLOC,,,,,,, 0, 0
|
|
_wr_u8 \arg
|
|
.endm
|
|
|
|
/**
|
|
* effects <headset:bool> <type:b2> <strongR:b1> <strongL:b1> <strongRvrbR:b1> <strongRvrbL:b1>
|
|
*
|
|
* Sets stereo effects.
|
|
*/
|
|
.macro effects headset, type, strongR, strongL, strongRvrbR, strongRvrbL
|
|
_check_arg_bitwidth_u \headset, 1
|
|
_check_arg_bitwidth_u \type, 2
|
|
_check_arg_bitwidth_u \strongR, 1
|
|
_check_arg_bitwidth_u \strongL, 1
|
|
_check_arg_bitwidth_u \strongRvrbR, 1
|
|
_check_arg_bitwidth_u \strongRvrbL, 1
|
|
|
|
_wr_cmd_id effects, ,ASEQ_OP_CHAN_EFFECTS,,,,,,, 0, 0
|
|
_wr_u8 (\headset << 7) | (\type << 4) | (\strongR << 3) | (\strongL << 2) | (\strongRvrbR << 1) | (\strongRvrbL << 0)
|
|
.endm
|
|
|
|
/**
|
|
* stptrtoseq <label:lbl>
|
|
*
|
|
* Stores TP -> label
|
|
*/
|
|
.macro stptrtoseq label
|
|
_wr_cmd_id stptrtoseq, ,ASEQ_OP_CHAN_STPTRTOSEQ,,,,,,, 0, 0
|
|
_wr_lbl \label
|
|
.endm
|
|
|
|
/**
|
|
* ldptr <label:lbl>
|
|
*
|
|
* Loads label -> TP
|
|
*/
|
|
.macro ldptr label
|
|
_wr_cmd_id ldptr, ,ASEQ_OP_CHAN_LDPTR,,,,,,, 0, 0
|
|
_wr_lbl \label
|
|
.endm
|
|
|
|
/**
|
|
* ldptr <imm:u16>
|
|
*
|
|
* Loads imm -> TP
|
|
*/
|
|
.macro ldptri imm
|
|
_wr_cmd_id ldptr, ,ASEQ_OP_CHAN_LDPTR,,,,,,, 0, 0
|
|
_wr_u16 \imm
|
|
.endm
|
|
|
|
/**
|
|
* rand <max:u8>
|
|
*
|
|
* Stores a random number in the range [0, max) into TR. If max is 0 the range is [0, 255]
|
|
*/
|
|
.macro rand max
|
|
_wr_cmd_id rand, ASEQ_OP_SEQ_RAND,ASEQ_OP_CHAN_RAND,,,,,,, 0, 0
|
|
_wr_u8 \max
|
|
.endm
|
|
|
|
/**
|
|
* [sequence] dyncall <table:lbl>
|
|
*
|
|
* Jumps to table[TR], treating table as a u16 array, pushing the next PC to the call stack
|
|
*
|
|
* [channel] dyncall
|
|
*
|
|
* Jumps to DYNTBL16[TR], pushing the next PC to the call stack
|
|
*/
|
|
.macro dyncall table=-1
|
|
.if \table == -1
|
|
_wr_cmd_id dyncall, ,ASEQ_OP_CHAN_DYNCALL,,,,,,, 0, 0
|
|
.else
|
|
_wr_cmd_id dyncall, ASEQ_OP_SEQ_DYNCALL,,,,,,,, 0, 0
|
|
_wr_lbl \table
|
|
.endif
|
|
.endm
|
|
|
|
/**
|
|
* ldi <imm:u8>
|
|
*
|
|
* Loads the immediate value `imm` into TR.
|
|
*/
|
|
.macro ldi imm
|
|
_wr_cmd_id ldi, ASEQ_OP_SEQ_LDI,ASEQ_OP_CHAN_LDI,,,,,,, 0, 0
|
|
_wr_u8 \imm
|
|
.endm
|
|
|
|
/**
|
|
* and <imm:u8>
|
|
*
|
|
* Computes TR = TR & imm
|
|
*/
|
|
.macro and imm
|
|
_wr_cmd_id and, ASEQ_OP_SEQ_AND,ASEQ_OP_CHAN_AND,,,,,,, 0, 0
|
|
_wr_u8 \imm
|
|
.endm
|
|
|
|
/**
|
|
* sub <imm:u8>
|
|
*
|
|
* Computes TR = TR - imm
|
|
*/
|
|
.macro sub imm
|
|
_wr_cmd_id sub, ASEQ_OP_SEQ_SUB,ASEQ_OP_CHAN_SUB,,,,,,, 0, 0
|
|
_wr_u8 \imm
|
|
.endm
|
|
|
|
/**
|
|
* stseq <imm:u8> <label:lbl>
|
|
*
|
|
* Stores the u8 value `TR + imm` to the location specified by `label`.
|
|
*/
|
|
.macro stseq imm, label
|
|
_wr_cmd_id stseq, ASEQ_OP_SEQ_STSEQ,ASEQ_OP_CHAN_STSEQ,,,,,,, 0, 0
|
|
_wr_u8 \imm
|
|
_wr_lbl \label
|
|
.endm
|
|
|
|
/**
|
|
* stop
|
|
*
|
|
* Immediately stops the sequence or channel.
|
|
*/
|
|
.macro stop
|
|
_wr_cmd_id stop, ASEQ_OP_SEQ_STOP,ASEQ_OP_CHAN_STOP,,,,,,, 0, 0
|
|
.endm
|
|
|
|
/**
|
|
* font <fontId:u8>
|
|
*
|
|
* Set the current soundfont for this channel to `fontId`.
|
|
*/
|
|
.macro font fontId
|
|
_wr_cmd_id font, ,ASEQ_OP_CHAN_FONT,,,,,,, 0, 0
|
|
_wr_u8 \fontId
|
|
.endm
|
|
|
|
/**
|
|
* scriptctr <arg:u16>
|
|
*
|
|
* Sets scriptCounter to arg.
|
|
*
|
|
* scriptCounter usually increments every time the sequence is updated but is otherwise
|
|
* never used, so changing it with this instruction has no useful effects.
|
|
*/
|
|
.macro scriptctr arg
|
|
_wr_cmd_id scriptctr, ASEQ_OP_SEQ_SCRIPTCTR,,,,,,,, 0, 0
|
|
_wr_u16 \arg
|
|
.endm
|
|
|
|
/**
|
|
* dyntbllookup
|
|
*
|
|
* Loads DYNTBL16[TR] -> DYNTBL
|
|
* unless TR is -1, in which case nothing happens.
|
|
*/
|
|
.macro dyntbllookup
|
|
_wr_cmd_id dyntbllookup, ,ASEQ_OP_CHAN_DYNTBLLOOKUP,,,,,,, 0, 0
|
|
.endm
|
|
|
|
/**
|
|
* runseq <seqPlayer:u8> <seqId:u8>
|
|
*
|
|
* Plays the sequence seqId on seqPlayer.
|
|
*/
|
|
.macro runseq seqPlayer, seqId
|
|
_wr_cmd_id runseq, ASEQ_OP_SEQ_RUNSEQ,,,,,,,, 0, 0
|
|
_wr_u8 \seqPlayer
|
|
_wr_u8 \seqId
|
|
.endm
|
|
|
|
#if (MML_VERSION == MML_VERSION_MM)
|
|
|
|
/**
|
|
* mutechan <arg0:s16>
|
|
*
|
|
* TODO DESCRIPTION
|
|
*/
|
|
.macro mutechan arg0
|
|
_wr_cmd_id mutechan, ASEQ_OP_SEQ_C3,,,,,,,, 0, 0
|
|
_wr_s16 \arg0
|
|
.endm
|
|
|
|
#endif
|
|
|
|
/**
|
|
* noshort
|
|
*
|
|
* Disable short notes encoding.
|
|
*/
|
|
.macro noshort
|
|
_wr_cmd_id noshort, ,ASEQ_OP_CHAN_NOSHORT,,,,,,, 0, 0
|
|
.endm
|
|
|
|
/**
|
|
* short
|
|
*
|
|
* Enable short notes encoding.
|
|
*/
|
|
.macro short
|
|
_wr_cmd_id short, ,ASEQ_OP_CHAN_SHORT,,,,,,, 0, 0
|
|
.endm
|
|
|
|
/**
|
|
* dyntbl <label:lbl>
|
|
*
|
|
* Loads label -> DYNTBL
|
|
*/
|
|
.macro dyntbl label
|
|
_wr_cmd_id dyntbl, ,ASEQ_OP_CHAN_DYNTBL,,,,,,, 0, 0
|
|
_wr_lbl \label
|
|
.endm
|
|
|
|
/**
|
|
* instr <instNum:u8>
|
|
*
|
|
* Set instrument `instNum` from the current soundfont as the active instrument for this channel or layer.
|
|
*/
|
|
.macro instr instNum
|
|
_wr_cmd_id instr, ,ASEQ_OP_CHAN_INSTR,ASEQ_OP_LAYER_INSTR,,,,,, 0, 0
|
|
_wr_u8 \instNum
|
|
.endm
|
|
|
|
#if (MML_VERSION == MML_VERSION_MM)
|
|
|
|
/**
|
|
* unk_BE <arg0:u8>
|
|
*
|
|
* TODO DESCRIPTION
|
|
*/
|
|
.macro unk_BE arg0
|
|
_wr_cmd_id unk_BE, ,ASEQ_OP_CHAN_UNK_BE,,,,,,, 0, 0
|
|
_wr_u8 \arg0
|
|
.endm
|
|
|
|
#endif
|
|
|
|
/**
|
|
* randptr <range:u16> <offset:u16>
|
|
*
|
|
* Assigns a random number sampled from [offset,offset+range) -> TP
|
|
*
|
|
* If range is 0, it is treated as 65536.
|
|
*/
|
|
.macro randptr range, offset
|
|
_wr_cmd_id randptr, ,ASEQ_OP_CHAN_RANDPTR,,,,,,, 0, 0
|
|
_wr_u16 \range
|
|
_wr_u16 \offset
|
|
.endm
|
|
|
|
#if (MML_VERSION == MML_VERSION_MM)
|
|
|
|
/**
|
|
* samplestart <arg0:u8>
|
|
*
|
|
* TODO DESCRIPTION
|
|
*/
|
|
.macro samplestart arg
|
|
_wr_cmd_id samplestart, ,ASEQ_OP_CHAN_SAMPLESTART,,,,,,, 0, 0
|
|
_wr_u8 \arg
|
|
.endm
|
|
|
|
/**
|
|
* unk_A7 <arg:u8>
|
|
*
|
|
* TODO DESCRIPTION
|
|
*/
|
|
.macro unk_A7 arg
|
|
_wr_cmd_id unk_A7, ,ASEQ_OP_CHAN_A7,,,,,,, 0, 0
|
|
_wr_u8 \arg
|
|
.endm
|
|
|
|
/**
|
|
* unk_A6 <arg0:u8> <arg1:s16>
|
|
*
|
|
* TODO DESCRIPTION
|
|
*/
|
|
.macro unk_A6 arg0, arg1
|
|
_wr_cmd_id unk_A6, ,ASEQ_OP_CHAN_A6,,,,,,, 0, 0
|
|
_wr_u8 \arg0
|
|
_wr_s16 \arg1
|
|
.endm
|
|
|
|
/**
|
|
* unk_A5
|
|
*
|
|
* TODO DESCRIPTION
|
|
*/
|
|
.macro unk_A5
|
|
_wr_cmd_id unk_A5, ,ASEQ_OP_CHAN_A5,,,,,,, 0, 0
|
|
.endm
|
|
|
|
/**
|
|
* unk_A4 <arg:u8>
|
|
*
|
|
* TODO DESCRIPTION
|
|
*/
|
|
.macro unk_A4 arg
|
|
_wr_cmd_id unk_A4, ,ASEQ_OP_CHAN_A4,,,,,,, 0, 0
|
|
_wr_u8 \arg
|
|
.endm
|
|
|
|
/**
|
|
* unk_A3
|
|
*
|
|
* TODO DESCRIPTION
|
|
*/
|
|
.macro unk_A3
|
|
_wr_cmd_id unk_A3, ,ASEQ_OP_CHAN_A3,,,,,,, 0, 0
|
|
.endm
|
|
|
|
/**
|
|
* unk_A2 <arg:s16>
|
|
*
|
|
* TODO DESCRIPTION
|
|
*/
|
|
.macro unk_A2 arg
|
|
_wr_cmd_id unk_A2, ,ASEQ_OP_CHAN_A2,,,,,,, 0, 0
|
|
_wr_s16 \arg
|
|
.endm
|
|
|
|
/**
|
|
* unk_A1
|
|
*
|
|
* TODO DESCRIPTION
|
|
*/
|
|
.macro unk_A1
|
|
_wr_cmd_id unk_A1, ,ASEQ_OP_CHAN_A1,,,,,,, 0, 0
|
|
.endm
|
|
|
|
/**
|
|
* unk_A0 <arg:s16>
|
|
*
|
|
* TODO DESCRIPTION
|
|
*/
|
|
.macro unk_A0 arg
|
|
_wr_cmd_id unk_A0, ,ASEQ_OP_CHAN_A0,,,,,,, 0, 0
|
|
_wr_s16 \arg
|
|
.endm
|
|
|
|
#endif
|
|
|
|
/**
|
|
* ptradd <value:lbl>
|
|
*
|
|
* Computes TP += value
|
|
*/
|
|
.macro ptradd value
|
|
_wr_cmd_id ptradd, ,ASEQ_OP_CHAN_PTRADD,,,,,,, 0, 0
|
|
_wr_lbl \value
|
|
.endm
|
|
|
|
/**
|
|
* ptraddi <value:u16>
|
|
*
|
|
* Like ptradd but for immediates instead of labels
|
|
*
|
|
* Computes TP += value
|
|
*/
|
|
.macro ptraddi value
|
|
_wr_cmd_id ptradd, ,ASEQ_OP_CHAN_PTRADD,,,,,,, 0, 0
|
|
_wr_u16 \value
|
|
.endm
|
|
|
|
/**
|
|
* combfilter <arg0:u8> <arg1:u16>
|
|
*
|
|
* Enable comb filter.
|
|
* TODO args? arg0=16,arg1=val<<8 maps well to midi chorus
|
|
*/
|
|
.macro combfilter arg0, arg1
|
|
_wr_cmd_id combfilter, ,ASEQ_OP_CHAN_COMBFILTER,,,,,,, 0, 0
|
|
_wr_u8 \arg0
|
|
_wr_u16 \arg1
|
|
.endm
|
|
|
|
/**
|
|
* randgate <range:u8>
|
|
*
|
|
* Sets the range of random note gateTime fluctuations.
|
|
*
|
|
* NOTE: This feature is bugged. If this is non-zero it will actually use the range set by randvel.
|
|
*/
|
|
.macro randgate range
|
|
_wr_cmd_id randgate, ,ASEQ_OP_CHAN_RANDGATE,,,,,,, 0, 0
|
|
_wr_u8 \range
|
|
.endm
|
|
|
|
/**
|
|
* randvel <range:u8>
|
|
*
|
|
* Sets the range for random note velocity fluctuations.
|
|
*/
|
|
.macro randvel range
|
|
_wr_cmd_id randvel, ,ASEQ_OP_CHAN_RANDVEL,,,,,,, 0, 0
|
|
_wr_u8 \range
|
|
.endm
|
|
|
|
/**
|
|
* rand <max:u16>
|
|
*
|
|
* Stores a random number in the range [0, max) into TP. If max is 0 the range is [0, 65535]
|
|
*/
|
|
.macro randtoptr max
|
|
_wr_cmd_id randtoptr, ,ASEQ_OP_CHAN_RANDTOPTR,,,,,,, 0, 0
|
|
_wr_u16 \max
|
|
.endm
|
|
|
|
/**
|
|
* dyntblv
|
|
*
|
|
* Loads DYNTBL8[TR] -> TR
|
|
*/
|
|
.macro dyntblv
|
|
_wr_cmd_id dyntblv, ,ASEQ_OP_CHAN_DYNTBLV,,,,,,, 0, 0
|
|
.endm
|
|
|
|
/**
|
|
* dyntbltoptr
|
|
*
|
|
* Loads DYNTBL16[TR] -> TP
|
|
*/
|
|
.macro dyntbltoptr
|
|
_wr_cmd_id dyntbltoptr, ,ASEQ_OP_CHAN_DYNTBLTOPTR,,,,,,, 0, 0
|
|
.endm
|
|
|
|
/**
|
|
* ptrtodyntbl
|
|
*
|
|
* Transfers TP -> DYNTBL
|
|
*/
|
|
.macro ptrtodyntbl
|
|
_wr_cmd_id ptrtodyntbl, ,ASEQ_OP_CHAN_PTRTODYNTBL,,,,,,, 0, 0
|
|
.endm
|
|
|
|
/**
|
|
* ldseqtoptr <label:lbl>
|
|
*
|
|
* Loads SEQ[label + TR * 2] -> TP
|
|
*
|
|
* Note that TR acts as an index into an array of u16 starting at label.
|
|
*/
|
|
.macro ldseqtoptr label
|
|
_wr_cmd_id ldseqtoptr, ,ASEQ_OP_CHAN_LDSEQTOPTR,,,,,,, 0, 0
|
|
_wr_lbl \label
|
|
.endm
|
|
|
|
/**
|
|
* freefilter
|
|
*
|
|
* Invalidates the current active filter buffer.
|
|
*/
|
|
.macro freefilter
|
|
_wr_cmd_id freefilter, ,ASEQ_OP_CHAN_FREEFILTER,,,,,,, 0, 0
|
|
.endm
|
|
|
|
/**
|
|
* ldfilter <filter:lbl>
|
|
*
|
|
* Sets the active filter buffer to the location specified by `filter`.
|
|
*/
|
|
.macro ldfilter filter
|
|
_wr_cmd_id ldfilter, ,ASEQ_OP_CHAN_LDFILTER,,,,,,, 0, 0
|
|
_wr_lbl \filter
|
|
.endm
|
|
|
|
/**
|
|
* cdelay <delay:b4>
|
|
*
|
|
* Short delay encoding for channel sections.
|
|
* Delays by `delay` ticks.
|
|
*/
|
|
.macro cdelay delay
|
|
_wr_cmd_id cdelay, ,ASEQ_OP_CHAN_CDELAY,,,,,,, \delay, 4
|
|
.endm
|
|
|
|
/**
|
|
* ldsample <portNum:b3>
|
|
*
|
|
* Triggers an async load of a sample belonging to either:
|
|
* - The Instrument ID in TR, if type is LDSAMPLE_INST.
|
|
* - The Sound Effect ID in TP, if type is LDSAMPLE_SFX.
|
|
*
|
|
* Load status is made available in CIO[CUR_CHANNEL][portNum].
|
|
*/
|
|
.macro ldsample type, portNum
|
|
.if \type == LDSAMPLE_INST
|
|
_wr_cmd_id ldsample, ,ASEQ_OP_CHAN_LDSAMPLE,,,,,,, \portNum, 3
|
|
.elif \type == LDSAMPLE_SFX
|
|
_wr_cmd_id ldsample, ,ASEQ_OP_CHAN_LDSAMPLE | 8,,,,,,, \portNum, 3
|
|
.else
|
|
.error "ldsample: invalid type"
|
|
.endif
|
|
.endm
|
|
#define LDSAMPLE_INST 0
|
|
#define LDSAMPLE_SFX 1
|
|
|
|
/**
|
|
* stcio <channelNum:b4> <portNum:u8>
|
|
*
|
|
* Stores the contents of TR into CIO[channelNum][portNum]
|
|
*/
|
|
.macro stcio channelNum, portNum
|
|
_wr_cmd_id stcio, ,ASEQ_OP_CHAN_STCIO,,,,,,, \channelNum, 4
|
|
_wr_u8 \portNum
|
|
.endm
|
|
|
|
/**
|
|
* ldcio <channelNum:b4> <portNum:u8>
|
|
*
|
|
* Loads the contents of CIO[channelNum][portNum] into TR.
|
|
*/
|
|
.macro ldcio channelNum, portNum
|
|
_wr_cmd_id ldcio, ,ASEQ_OP_CHAN_LDCIO,,,,,,, \channelNum, 4
|
|
_wr_u8 \portNum
|
|
.endm
|
|
|
|
/**
|
|
* rldlayer <layerNum:b3> <label:rel_lbl>
|
|
*
|
|
* Opens the note layer at `label` for index `layerNum`.
|
|
* `label` is a relative offset rather than an absolute offset, making it appropriate
|
|
* for use in position-independent code.
|
|
*/
|
|
.macro rldlayer layerNum, label
|
|
_wr_cmd_id rldlayer, ,ASEQ_OP_CHAN_RLDLAYER,,,,,,, \layerNum, 3
|
|
_wr_16_rel \label
|
|
.endm
|
|
|
|
/**
|
|
* testlayer <layerNum:b3>
|
|
*
|
|
* Tests if the layer specified by `layerNum` is finished.
|
|
* Stores result to TR:
|
|
* - 1 if layer is finished.
|
|
* - 0 if layer is not finished.
|
|
* - -1 if layer does not exist.
|
|
*/
|
|
.macro testlayer layerNum
|
|
_wr_cmd_id testlayer, ,ASEQ_OP_CHAN_TESTLAYER,,,,,,, \layerNum, 3
|
|
.endm
|
|
|
|
/**
|
|
* ldlayer <layerNum:b3> <label:lbl>
|
|
*
|
|
* Opens the note layer at `label` for index `layerNum`.
|
|
*/
|
|
.macro ldlayer layerNum, label
|
|
_wr_cmd_id ldlayer, ,ASEQ_OP_CHAN_LDLAYER,,,,,,, \layerNum, 3
|
|
_wr_lbl \label
|
|
.endm
|
|
|
|
/**
|
|
* dellayer <layerNum:b3>
|
|
*
|
|
* Deletes the layer specified by index `layerNum`.
|
|
*/
|
|
.macro dellayer arg
|
|
_wr_cmd_id dellayer, ,ASEQ_OP_CHAN_DELLAYER,,,,,,, \arg, 3
|
|
.endm
|
|
|
|
/**
|
|
* dynldlayer <arg:b3>
|
|
*
|
|
* Allocates a new layer starting at the pointer read from DYNTBL16[TR]
|
|
*/
|
|
.macro dynldlayer arg
|
|
_wr_cmd_id dynldlayer, ,ASEQ_OP_CHAN_DYNLDLAYER,,,,,,, \arg, 3
|
|
.endm
|
|
|
|
/**
|
|
* testchan <channelNum:b4>
|
|
*
|
|
* Tests if the channel specified by index `channelNum` is enabled.
|
|
* Stores result to TR:
|
|
* - 0 if enabled
|
|
* - 1 if disabled
|
|
*/
|
|
.macro testchan channelNum
|
|
_wr_cmd_id testchan, ASEQ_OP_SEQ_TESTCHAN,,,,,,,, \channelNum, 4
|
|
.endm
|
|
|
|
/**
|
|
* stopchan <channelNum:b4>
|
|
*
|
|
* Disables the channel specified by channel `channelNum`.
|
|
*/
|
|
.macro stopchan channelNum
|
|
.if ASEQ_MODE == ASEQ_MODE_SEQUENCE
|
|
_wr_cmd_id stopchan, ASEQ_OP_SEQ_STOPCHAN,,,,,,,, \channelNum, 4
|
|
.else
|
|
_wr_cmd_id stopchan, ,ASEQ_OP_CHAN_STOPCHAN,,,,,,, 0, 0
|
|
_wr_u8 \channelNum
|
|
.endif
|
|
.endm
|
|
|
|
/**
|
|
* subio <portNum:b4>
|
|
*
|
|
* In sequence section:
|
|
* Computes TR = TR - SIO[portNum]
|
|
*
|
|
* In channel section:
|
|
* Computes TR = TR - CIO[CUR_CHANNEL][portNum]
|
|
*/
|
|
.macro subio portNum
|
|
_wr_cmd_id subio, ASEQ_OP_SEQ_SUBIO,ASEQ_OP_CHAN_SUBIO,,,,,,, \portNum, 4
|
|
.endm
|
|
|
|
/**
|
|
* ldres <portNum:b4> <resType:u8> <resId:u8>
|
|
*
|
|
* Load Resource.
|
|
* resType (sync with SampleBankTableType)
|
|
* - 0 = Sequence
|
|
* - 1 = Font
|
|
* - 2 = Sample
|
|
*
|
|
* resId is either a sequence id, soundfont id or samplebank id.
|
|
*
|
|
* Load status is made available in SIO[portNum].
|
|
*/
|
|
.macro ldres portNum, resType, resId
|
|
_wr_cmd_id ldres, ASEQ_OP_SEQ_LDRES,,,,,,,, \portNum, 4
|
|
_wr_u8 \resType
|
|
_wr_u8 \resId
|
|
.endm
|
|
|
|
/**
|
|
* Sequence Section: stio <portNum:b4>
|
|
* Channel Section: stio <portNum:b3>
|
|
*
|
|
* Moves the contents of TR to either SIO[portNum] or CIO[CUR_CHANNEL][portNum]
|
|
* depending on current section.
|
|
*/
|
|
.macro stio portNum
|
|
.if ASEQ_MODE == ASEQ_MODE_CHANNEL
|
|
_wr_cmd_id stio, ,ASEQ_OP_CHAN_STIO,,,,,,, \portNum, 3
|
|
.else
|
|
_wr_cmd_id stio, ASEQ_OP_SEQ_STIO,,,,,,,, \portNum, 4
|
|
.endif
|
|
.endm
|
|
|
|
/**
|
|
* ldio <portNum:b4>
|
|
*
|
|
* Moves the contents of either SIO[portNum] or CIO[CUR_CHANNEL][portNum] to TR
|
|
* depending on current section.
|
|
*/
|
|
.macro ldio portNum
|
|
_wr_cmd_id ldio, ASEQ_OP_SEQ_LDIO,ASEQ_OP_CHAN_LDIO,,,,,,, \portNum, 4
|
|
.endm
|
|
|
|
/**
|
|
* ldchan <channelNum:b4> <label:lbl>
|
|
*
|
|
* Opens the sequence channel for index `channelNum` with data beginning at `label`.
|
|
*/
|
|
.macro ldchan channelNum, label
|
|
_wr_cmd_id ldchan, ASEQ_OP_SEQ_LDCHAN,ASEQ_OP_CHAN_LDCHAN,,,,,,, \channelNum, 4
|
|
_wr_lbl \label
|
|
.endm
|
|
|
|
/**
|
|
* rldchan <channelNum:b4> <label:rel_lbl>
|
|
*
|
|
* Opens the sequence channel for index `channelNum` with data beginning at `label`.
|
|
* `label` is a relative offset rather than an absolute offset, making it appropriate
|
|
* for use in position-independent code.
|
|
*/
|
|
.macro rldchan channelNum, label
|
|
_wr_cmd_id rldchan, ASEQ_OP_SEQ_RLDCHAN,,,,,,,, \channelNum, 4
|
|
_wr_16_rel \label
|
|
.endm
|
|
|
|
/**
|
|
* ldelay <delay:var>
|
|
*
|
|
* Delay for `delay` ticks.
|
|
*/
|
|
.macro ldelay delay
|
|
_wr_cmd_id ldelay, ,,ASEQ_OP_LAYER_LDELAY,,,,,, 0, 0
|
|
_var \delay
|
|
.endm
|
|
|
|
/**
|
|
* Workaround for bugged delays using a larger encoding than is needed.
|
|
* Acts like ldelay but forces a long var encoding even if the arg can fit
|
|
* in a smaller encoding.
|
|
* Should never be used when not required for matching purposes.
|
|
*/
|
|
.macro lldelay delay
|
|
_wr_cmd_id lldelay, ,ASEQ_OP_DELAY,ASEQ_OP_LAYER_LDELAY,,,,,, 0, 0
|
|
_var_long \delay
|
|
.endm
|
|
|
|
/**
|
|
* shortvel <velocity:u8>
|
|
*
|
|
* Set velocity used by short notes.
|
|
*/
|
|
.macro shortvel velocity
|
|
_wr_cmd_id shortvel, ,,ASEQ_OP_LAYER_SHORTVEL,,,,,, 0, 0
|
|
_wr_u8 \velocity
|
|
.endm
|
|
|
|
/**
|
|
* shortdelay <delay:var>
|
|
*
|
|
* Set delay used by short notes.
|
|
*/
|
|
.macro shortdelay delay
|
|
_wr_cmd_id shortdelay, ,,ASEQ_OP_LAYER_SHORTDELAY,,,,,, 0, 0
|
|
_var \delay
|
|
.endm
|
|
|
|
/**
|
|
* legato
|
|
*
|
|
* Enables legato on the current layer.
|
|
*/
|
|
.macro legato
|
|
_wr_cmd_id legato, ,,ASEQ_OP_LAYER_LEGATO,,,,,, 0, 0
|
|
.endm
|
|
|
|
/**
|
|
* nolegato
|
|
*
|
|
* Disables legato on the current layer.
|
|
*/
|
|
.macro nolegato
|
|
_wr_cmd_id nolegato, ,,ASEQ_OP_LAYER_NOLEGATO,,,,,, 0, 0
|
|
.endm
|
|
|
|
/**
|
|
* portamento <mode> <target:u8> <time:u8/var>
|
|
*
|
|
* The time argument is either a var or a u8 depending on mode
|
|
*/
|
|
.macro portamento mode, target, time
|
|
_wr_cmd_id portamento, ,,ASEQ_OP_LAYER_PORTAMENTO,,,,,, 0, 0
|
|
_wr_u8 \mode
|
|
_wr_u8 \target
|
|
.if (\mode & 0x80) != 0
|
|
_wr_u8 \time
|
|
.else
|
|
_var \time
|
|
.endif
|
|
.endm
|
|
|
|
/**
|
|
* noportamento
|
|
*
|
|
* Disables portamento on the current layer.
|
|
*/
|
|
.macro noportamento
|
|
_wr_cmd_id noportamento, ,,ASEQ_OP_LAYER_NOPORTAMENTO,,,,,, 0, 0
|
|
.endm
|
|
|
|
/**
|
|
* shortgate <gateTime:u8>
|
|
*
|
|
* Sets gate time for short notes.
|
|
*/
|
|
.macro shortgate gateTime
|
|
_wr_cmd_id shortgate, ,,ASEQ_OP_LAYER_SHORTGATE,,,,,, 0, 0
|
|
_wr_u8 \gateTime
|
|
.endm
|
|
|
|
/**
|
|
* notepan <pan:u8>
|
|
*
|
|
* Sets the pan for this layer. A value of 64 is center.
|
|
*/
|
|
.macro notepan pan
|
|
/* pan can only take values in 0..127 */
|
|
_check_arg_bitwidth_u \pan, 7
|
|
_wr_cmd_id notepan, ,,ASEQ_OP_LAYER_NOTEPAN,,,,,, 0, 0
|
|
_wr_u8 \pan
|
|
.endm
|
|
|
|
/**
|
|
* nodrumpan
|
|
*
|
|
* Instructs the layer to ignore the pan value in drum instruments and only
|
|
* use pan set in the layer.
|
|
*/
|
|
.macro nodrumpan
|
|
_wr_cmd_id nodrumpan, ,,ASEQ_OP_LAYER_NODRUMPAN,,,,,, 0, 0
|
|
.endm
|
|
|
|
/**
|
|
* stereo <type:b2> <strongR:b1> <strongL:b1> <strongRvrbR:b1> <strongRvrbL:b1>
|
|
*
|
|
* TODO DESCRIPTION
|
|
*/
|
|
.macro stereo type, strongR, strongL, strongRvrbR, strongRvrbL
|
|
_check_arg_bitwidth_u \type, 2
|
|
_check_arg_bitwidth_u \strongR, 1
|
|
_check_arg_bitwidth_u \strongL, 1
|
|
_check_arg_bitwidth_u \strongRvrbR, 1
|
|
_check_arg_bitwidth_u \strongRvrbL, 1
|
|
|
|
_wr_cmd_id stereo, ,,ASEQ_OP_LAYER_STEREO,,,,,, 0, 0
|
|
_wr_u8 (\type << 4) | (\strongR << 3) | (\strongL << 2) | (\strongRvrbR << 1) | (\strongRvrbL << 0)
|
|
.endm
|
|
|
|
/**
|
|
* ldshortvel <velocity:b4>
|
|
*
|
|
* Sets the velocity used in short notes by reading from SHORTVELTBL[velocity]
|
|
*/
|
|
.macro ldshortvel velocity
|
|
_wr_cmd_id ldshortvel, ,,ASEQ_OP_LAYER_LDSHORTVEL,,,,,, \velocity, 4
|
|
.endm
|
|
|
|
/**
|
|
* ldshortgate <gateTime:b4>
|
|
*
|
|
* Sets the gate time used in short notes by reading from SHORTGATETBL[gateTime]
|
|
*/
|
|
.macro ldshortgate gateTime
|
|
_wr_cmd_id ldshortgate, ,,ASEQ_OP_LAYER_LDSHORTGATE,,,,,, \gateTime, 4
|
|
.endm
|
|
|
|
#if (MML_VERSION == MML_VERSION_MM)
|
|
|
|
/**
|
|
* unk_F0 <arg:s16>
|
|
*
|
|
* TODO DESCRIPTION
|
|
*/
|
|
.macro unk_F0 arg
|
|
_wr_cmd_id unk_F0, ,,ASEQ_OP_LAYER_F0,,,,,, 0, 0
|
|
_wr_s16 \arg
|
|
.endm
|
|
|
|
/**
|
|
* surroundeffect <arg:u8>
|
|
*
|
|
* TODO DESCRIPTION
|
|
*/
|
|
.macro surroundeffect arg
|
|
_wr_cmd_id surroundeffect, ,,ASEQ_OP_LAYER_F1,,,,,, 0, 0
|
|
_wr_u8 \arg
|
|
.endm
|
|
|
|
#endif
|
|
|
|
/**
|
|
* notedvg <pitch:b6> <delay:var> <velocity:u8> <gateTime:u8>
|
|
*
|
|
* Plays a note with the current instrument settings for a specified length of time.
|
|
*
|
|
* pitch : The note to play. Since pitch is only 6 bits it can only hold values 0..63, for access to more values
|
|
* use `transpose` first to shift the base pitch.
|
|
* delay : The time to play the note for, plus the delay before executing the next instruction.
|
|
* velocity : The relative volume.
|
|
* gateTime : The proportion of the delay for which the sound does not play.
|
|
*
|
|
* This instruction must only be used when long notes are enabled with the noshort instruction.
|
|
*/
|
|
.macro notedvg pitch, delay, velocity, gateTime
|
|
_wr_cmd_id notedvg, ,,ASEQ_OP_LAYER_NOTEDVG,,,,,, \pitch, 6
|
|
_var \delay
|
|
_wr_u8 \velocity
|
|
_wr_u8 \gateTime
|
|
.endm
|
|
|
|
/**
|
|
* notedv <pitch:b6> <delay:var> <velocity:u8>
|
|
*
|
|
* Like notedvg, but gateTime is fixed to 0 so there is no delay between when the sound stops and the next instruction.
|
|
*
|
|
* This instruction must only be used when long notes are enabled with the noshort instruction.
|
|
*/
|
|
.macro notedv pitch, delay, velocity
|
|
_wr_cmd_id notedv, ,,ASEQ_OP_LAYER_NOTEDV,,,,,, \pitch, 6
|
|
_var \delay
|
|
_wr_u8 \velocity
|
|
.endm
|
|
|
|
/* Workaround for bugs in vanilla sequences, force long encoding for delay. This should not typically be used. */
|
|
.macro noteldv pitch, delay, velocity
|
|
_wr_cmd_id noteldv, ,,ASEQ_OP_LAYER_NOTEDV,,,,,, \pitch, 6
|
|
_var_long \delay
|
|
_wr_u8 \velocity
|
|
.endm
|
|
|
|
/**
|
|
* notevg <pitch:b6> <velocity:u8> <gateTime:u8>
|
|
*
|
|
* Like notedvg, but delay is assumed to be the same as the delay for a previous note instruction.
|
|
*
|
|
* This instruction must only be used when long notes are enabled with the noshort instruction.
|
|
*/
|
|
.macro notevg pitch, velocity, gateTime
|
|
_wr_cmd_id notevg, ,,ASEQ_OP_LAYER_NOTEVG,,,,,, \pitch, 6
|
|
_wr_u8 \velocity
|
|
_wr_u8 \gateTime
|
|
.endm
|
|
|
|
/**
|
|
* shortdvg <pitch:b6> <delay:var>
|
|
*
|
|
* Like notedvg, but encodes shorter by requiring that the velocity and gateTime be specified in advance using the
|
|
* shortvel and shortgate instructions.
|
|
*
|
|
* This instruction must only be used when short notes are enabled with the short instruction.
|
|
*/
|
|
.macro shortdvg pitch, delay
|
|
_wr_cmd_id shortdvg, ,,ASEQ_OP_LAYER_NOTEDVG,,,,,, \pitch, 6
|
|
_var \delay
|
|
.endm
|
|
|
|
/**
|
|
* shortdv <pitch:b6>
|
|
*
|
|
* Like shortdvg, but gateTime is fixed to 0 so there is no delay between when the sound stops and the next
|
|
* instruction. Uses the delay set by shortdelay, and the velocity set by shortvel.
|
|
*
|
|
* This instruction must only be used when short notes are enabled with the short instruction.
|
|
*/
|
|
.macro shortdv pitch
|
|
_wr_cmd_id shortdv, ,,ASEQ_OP_LAYER_NOTEDV,,,,,, \pitch, 6
|
|
.endm
|
|
|
|
/**
|
|
* shortvg <pitch:b6>
|
|
*
|
|
* Like shortdvg, but delay is assumed to be the same as the delay for a previous note instruction. Uses the velocity
|
|
* set by shortvel.
|
|
*
|
|
* This instruction must only be used when short notes are enabled with the short instruction.
|
|
*/
|
|
.macro shortvg pitch
|
|
_wr_cmd_id shortvg, ,,ASEQ_OP_LAYER_NOTEVG,,,,,, \pitch, 6
|
|
.endm
|
|
|
|
/**
|
|
* entry <label:lbl>
|
|
*
|
|
* For dyntable entries.
|
|
*/
|
|
.macro entry label
|
|
_wr_lbl \label
|
|
.endm
|
|
|
|
/**
|
|
* point <delay:s16> <arg:s16>
|
|
*
|
|
* Envelope point
|
|
*/
|
|
.macro point delay, arg
|
|
.if ASEQ_MODE != ASEQ_MODE_ENVELOPE
|
|
_section_invalid point
|
|
.endif
|
|
|
|
_wr_s16 \delay
|
|
_wr_s16 \arg
|
|
.endm
|
|
|
|
/**
|
|
* disable
|
|
*
|
|
* Envelope disable
|
|
*/
|
|
.macro disable
|
|
.if ASEQ_MODE != ASEQ_MODE_ENVELOPE
|
|
_section_invalid disable
|
|
.endif
|
|
|
|
_wr_u16 0
|
|
_wr_s16 0
|
|
.endm
|
|
|
|
/**
|
|
* hang
|
|
*
|
|
* Envelope hang
|
|
*/
|
|
.macro hang
|
|
.if ASEQ_MODE != ASEQ_MODE_ENVELOPE
|
|
_section_invalid hang
|
|
.endif
|
|
|
|
_wr_u16 0xFFFF // -1
|
|
_wr_s16 0
|
|
.endm
|
|
|
|
/**
|
|
* goto <index:s16>
|
|
*
|
|
* Envelope goto
|
|
*/
|
|
.macro goto index
|
|
.if ASEQ_MODE != ASEQ_MODE_ENVELOPE
|
|
_section_invalid goto
|
|
.endif
|
|
|
|
_wr_u16 0xFFFE // -2
|
|
_wr_s16 \index
|
|
.endm
|
|
|
|
/**
|
|
* restart
|
|
*
|
|
* Envelope restart
|
|
*/
|
|
.macro restart
|
|
.if ASEQ_MODE != ASEQ_MODE_ENVELOPE
|
|
_section_invalid restart
|
|
.endif
|
|
|
|
_wr_u16 0xFFFD // -3
|
|
_wr_s16 0
|
|
.endm
|
|
|
|
#endif /* _LANGUAGE_ASEQ */
|
|
|
|
#endif /* ASEQ_H */
|