mirror of https://github.com/zeldaret/mm.git
				
				
				
			
		
			
				
	
	
		
			2519 lines
		
	
	
		
			63 KiB
		
	
	
	
		
			GAS
		
	
	
	
			
		
		
	
	
			2519 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"
 | |
|         .balign 4
 | |
|     .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 & 0xFFFF
 | |
| .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:s16>
 | |
|  *
 | |
|  *  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_s16     \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 */
 |