implement all commands

no playback yet!
This commit is contained in:
tildearrow 2025-04-05 18:19:41 -05:00
parent fd9c935fc7
commit d7922baa07
4 changed files with 606 additions and 242 deletions

View file

@ -32,6 +32,21 @@ program follows.
### commands/instructions
command parameters (including their types) are indicated within parentheses. for example, (cs) means "read a char (8-bit) and a short (16-bit)".
the types are:
- `c`: signed char
- `s`: signed short (16-bit)
- `i`: signed int (32-bit)
- `b`: unsigned char (byte)
- `S`: unsigned short
- `U`: unsigned int
- `X`: custom (described under the command name)
the command list follows.
```
hex | description
----|------------------------------------
@ -47,22 +62,28 @@ hex | description
b5 | note off
b6 | note off env
b7 | env release
b8 | instrument // (ins, force)
c0 | pre porta // (inporta, isportaorslide)
c2 | vibrato // (speed, depth)
c3 | vibrato range // (range)
c4 | vibrato shape // (shape)
c5 | pitch // (pitch)
c6 | arpeggio // (note1, note2)
c7 | volume // (vol)
c8 | vol slide // (amount)
c9 | porta // (target, speed)
ca | legato // (note)
cb | volume slide with target // (amount, target)
cc | tremolo // (speed/depth)
cd | panbrello // (speed/depth)
ce | pan slide // (speed)
cf | panning // (left, right)
b8 | instrument (b)
c0 | pre porta (X)
| - bit 7: inPorta
| - bit 6: isPortaOrSlide
c2 | vibrato (bb) // speed, depth
c3 | vibrato range (b)
c4 | vibrato shape (b)
c5 | pitch (c)
c6 | arpeggio (bb) // note1, note2
c7 | volume (b)
c8 | vol slide (s)
c9 | porta (bb) // target, speed
ca | legato (b) // note... $ff is null note
cb | volume slide with target (sS) // amount, target
cc | tremolo (X)
| - bit 4-7: speed
| - bit 0-3: depth
cd | panbrello (X)
| - bit 4-7: speed
| - bit 0-3: depth
ce | pan slide (c)
cf | panning (bb) // left, right
----|------------------------------------
d0 | speed dial command 0
d1 | speed dial command 1
@ -97,270 +118,280 @@ hex | description
```
hex | description
----|------------------------------------
1c | sample mode
1d | sample freq
1e | legacy sample bank
1f | sample position
20 | sample direction
1c | sample mode (b)
1d | sample freq (b)
1e | legacy sample bank (b)
1f | sample position (U)
20 | sample direction (b)
----|------------------------------------
| **FM commands**
21 | hard reset
22 | LFO speed
23 | LFO waveform
24 | TL
25 | AM
26 | AR
27 | DR
28 | SL
29 | D2R
2a | RR
2b | DT
2c | DT2
2d | RS
2e | KSR
2f | VIB
30 | SUS
31 | WS
32 | SSG-EG
33 | REV
34 | EG-Shift
35 | FB
36 | MULT
37 | FINE
38 | fixed frequency
39 | ExtCh
3a | AM depth
3b | PM depth
3c | LFO2 speed
3d | LFO2 wave
21 | hard reset (b)
22 | LFO speed (b)
23 | LFO waveform (b)
24 | TL (bb)
25 | AM (bb)
26 | AR (bb)
27 | DR (bb)
28 | SL (bb)
29 | D2R (bb)
2a | RR (bb)
2b | DT (bb)
2c | DT2 (bb)
2d | RS (bb)
2e | KSR (bb)
2f | VIB (bb)
30 | SUS (bb)
31 | WS (bb)
32 | SSG-EG (bb)
33 | REV (bb)
34 | EG-Shift (bb)
35 | FB (b)
36 | MULT (bb)
37 | FINE (bb)
38 | fixed frequency (XX)
| - byte 0: frequency low
| - byte 1:
| - bit 4-5: operator
| - bit 0-2: frequency high
39 | ExtCh (b)
3a | AM depth (b)
3b | PM depth (b)
3c | LFO2 speed (b)
3d | LFO2 wave (b)
----|------------------------------------
| **PSG commands**
3e | noise freq
3f | noise mode/duty/whatever
40 | waveform
3e | noise freq (b)
3f | noise mode/duty/whatever (b)
40 | waveform (b)
----|------------------------------------
| **Game Boy commands**
41 | sweep time
42 | sweep direction
41 | sweep time (b)
42 | sweep direction (b)
----|------------------------------------
| **PC Engine commands**
43 | LFO mode
44 | LFO speed
43 | LFO mode (b)
44 | LFO speed (b)
----|------------------------------------
| **NES commands**
45 | sweep
46 | set DMC
45 | sweep (X)
| - bit 3: on
| - rest of bits: sweep time/amount
46 | set DMC (b)
----|------------------------------------
| **C64 commands**
47 | coarse cutoff
48 | resonance
49 | filter mode
4a | reset time
4b | reset mask
4c | filter reset
4d | duty reset
4e | extended
4f | duty
50 | cutoff
47 | coarse cutoff (b)
48 | resonance (b)
49 | filter mode (b)
4a | reset time (b)
4b | reset mask (b)
4c | filter reset (b)
4d | duty reset (b)
4e | extended (b)
4f | duty (S)
50 | cutoff (S)
----|------------------------------------
| **AY commands**
51 | set envelope
52 | envelope freq low
53 | envelope freq high
54 | envelope slide
55 | noise AND mask
56 | noise OR mask
57 | auto envelope
58 | I/O port write
59 | AutoPWM
51 | set envelope (b)
52 | envelope freq low (b)
53 | envelope freq high (b)
54 | envelope slide (b)
55 | noise AND mask (b)
56 | noise OR mask (b)
57 | auto envelope (b)
58 | I/O port write (bb)
59 | AutoPWM (bb)
----|------------------------------------
| **FDS commands**
5a | mod depth
5b | mod speed high
5c | mod speed low
5d | mod position
5e | mod waveform
5a | mod depth (b)
5b | mod speed high (b)
5c | mod speed low (b)
5d | mod position (b)
5e | mod waveform (b)
----|------------------------------------
| **SAA1099 commands**
5f | envelope
5f | envelope (b)
----|------------------------------------
| **Amiga commands**
60 | toggle filter
61 | AM
62 | period modulation
60 | toggle filter (b)
61 | AM (b)
62 | period modulation (b)
----|------------------------------------
| **Lynx commands**
63 | load LFSR
63 | load LFSR (S)
----|------------------------------------
| **QSound commands**
64 | echo feedback
65 | echo delay
66 | echo level
67 | surround
64 | echo feedback (b)
65 | echo delay (S)
66 | echo level (b)
67 | surround (b)
----|------------------------------------
| **X1-010 commands**
68 | envelope shape
69 | envelope enable
6a | envelope mode
6b | envelope period
6c | envelope slide
6d | auto envelope
6e | sample bank slot
68 | envelope shape (b)
69 | UNUSED - envelope enable (b)
6a | envelope mode (b)
6b | envelope period (b)
6c | envelope slide (b)
6d | auto envelope (b)
6e | sample bank slot (b)
----|------------------------------------
| **WonderSwan commands**
6f | sweep time
70 | sweep amount
6f | sweep time (b)
70 | sweep amount (b)
----|------------------------------------
| **Namco 163 commands**
71 | wave position
72 | wave length
73 | UNUSED
74 | UNUSED
75 | wave load position
76 | wave load length
77 | UNUSED
78 | channel limit
79 | global wave load
7a | global wave load position
7b | UNUSED
7c | UNUSED
71 | wave position (b)
72 | wave length (b)
73 | UNUSED (b)
74 | UNUSED (b)
75 | wave load position (b)
76 | wave load length (b)
77 | UNUSED (b)
78 | channel limit (b)
79 | global wave load (b)
7a | global wave load position (b)
7b | UNUSED (b)
7c | UNUSED (b)
----|------------------------------------
| **Sound Unit commands**
7d | sweep period low
7e | sweep period high
7f | sweep bound
80 | sweep enable
81 | sync period low
82 | sync period high
7d | sweep period low (bb)
7e | sweep period high (bb)
7f | sweep bound (bb)
80 | sweep enable (bb)
81 | sync period low (b)
82 | sync period high (b)
----|------------------------------------
83 | ADPCM-A volume
83 | ADPCM-A volume (b)
----|------------------------------------
| **SNES commands**
84 | echo
85 | pitch mod
86 | invert
87 | gain mode
88 | gain
89 | echo enable
8a | echo delay
8b | echo vol left
8c | echo vol right
8d | echo feedback
8e | echo filter
84 | echo (b)
85 | pitch mod (b)
86 | invert (b)
87 | gain mode (b)
88 | gain (b)
89 | echo enable (b)
8a | echo delay (b)
8b | echo vol left (c)
8c | echo vol right (c)
8d | echo feedback (c)
8e | echo filter (bc)
----|------------------------------------
| **NES commands (continued)**
8f | envelope mode
90 | length counter
91 | count mode (?)
8f | envelope mode (b)
90 | length counter (b)
91 | frame counter rate/count mode (b)
----|------------------------------------
| **macro control**
92 | macro off
93 | macro on
92 | macro off (b)
93 | macro on (b)
----|------------------------------------
94 | surround panning
94 | surround panning (bb)
----|------------------------------------
| **FM commands (continued)**
95 | AM depth 2
96 | PM depth 2
95 | AM depth 2 (b)
96 | PM depth 2 (b)
----|------------------------------------
| **ES5506 commands**
97 | filter mode
98 | filter K1
99 | filter K2
9a | filter K1 slide
9b | filter K2 slide
9c | envelope count
9d | envelope left vol ramp
9e | envelope right vol ramp
9f | envelope K1 ramp
a0 | envelope K2 ramp
a1 | pause
97 | filter mode (b)
98 | filter K1 (SS)
99 | filter K2 (SS)
9a | filter K1 slide (bb)
9b | filter K2 slide (bb)
9c | envelope count (S)
9d | envelope left vol ramp (b)
9e | envelope right vol ramp (b)
9f | envelope K1 ramp (bb)
a0 | envelope K2 ramp (bb)
a1 | pause (b)
----|------------------------------------
a2 | arpeggio speed
a2 | arpeggio speed (b)
----|------------------------------------
| **SNES commands (continued)**
a3 | global vol left
a4 | global vol right
a3 | global vol left (c)
a4 | global vol right (c)
----|------------------------------------
a5 | NES linear counter length
a5 | NES linear counter length (b)
----|------------------------------------
a6 | external command
a6 | external command (b)
----|------------------------------------
| **C64 commands (continued)**
a7 | attack/decay
a8 | sustain/release
a7 | attack/decay (X)
| - bit 4-7: attack
| - bit 0-3: decay
a8 | sustain/release (X)
| - bit 4-7: sustain
| - bit 0-3: release
----|------------------------------------
| **ESFM commands**
a9 | operator panning
aa | output level
ab | modulation input
ac | envelope delay
a9 | operator panning (bb)
aa | output level (bb)
ab | modulation input (bb)
ac | envelope delay (bb)
----|------------------------------------
ad | restart macro
ad | restart macro (b)
----|------------------------------------
| **PowerNoise commands**
ae | load counter
af | I/O write
ae | load counter (bb)
af | I/O write (bb)
----|------------------------------------
| **Dave commands**
b0 | high pass
b1 | ring mod
b2 | swap counters
b3 | low pass
b4 | clock divider
b0 | high pass (b)
b1 | ring mod (b)
b2 | swap counters (b)
b3 | low pass (b)
b4 | clock divider (b)
----|------------------------------------
b5 | MinMod echo setup
b5 | MinMod echo setup (b)
----|------------------------------------
| **Bifurcator commands**
b6 | state load
b7 | set parameter
b6 | state load (bb)
b7 | set parameter (bb)
----|------------------------------------
b8 | FDS auto mod
b8 | FDS auto mod (b)
----|------------------------------------
b9 | FM operator mask
b9 | FM operator mask (b)
----|------------------------------------
| **MultiPCM commands**
ba | mix FM
bb | mix PCM
bc | LFO
bd | VIB
be | AM
bf | AR
c0 | D1R
c1 | DL
c2 | D2R
c3 | RC
c4 | RR
c5 | damp
c6 | pseudo-reverb
c7 | LFO reset
c8 | level direct
ba | mix FM (b)
bb | mix PCM (b)
bc | LFO (b)
bd | VIB (b)
be | AM (b)
bf | AR (b)
c0 | D1R (b)
c1 | DL (b)
c2 | D2R (b)
c3 | RC (b)
c4 | RR (b)
c5 | damp (b)
c6 | pseudo-reverb (b)
c7 | LFO reset (b)
c8 | level direct (b)
----|------------------------------------
| **SID3 commands**
c9 | special wave
ca | ring mod source
cb | hard sync source
cc | phase mod source
cd | wave mix
ce | LFSR feedback bits
cf | 1-bit noise
d0 | filter distortion
d1 | filter output volume
d2 | channel invert
d3 | filter connection
d4 | filter matrix
d5 | filter enable
c9 | special wave (b)
ca | ring mod source (b)
cb | hard sync source (b)
cc | phase mod source (b)
cd | wave mix (b)
ce | LFSR feedback bits (bb)
cf | 1-bit noise (b)
d0 | filter distortion (bb)
d1 | filter output volume (bb)
d2 | channel invert (b)
d3 | filter connection (b)
d4 | filter matrix (b)
d5 | filter enable (b)
----|------------------------------------
| **slide commands**
d6 | pulse width slide
d7 | cutoff slide
d6 | pulse width slide (bc)
d7 | cutoff slide (bc)
----|------------------------------------
| **SID3 commands (continued)**
d8 | phase reset
d9 | noise phase reset
da | envelope reset
db | cutoff scaling
dc | resonance scaling
d8 | phase reset (b)
d9 | noise phase reset (b)
da | envelope reset (b)
db | cutoff scaling (b)
dc | resonance scaling (b)
----|------------------------------------
dd | WonderSwan speaker volume
dd | WonderSwan speaker volume (b)
```

View file

@ -105,7 +105,8 @@ class DivCSPlayer {
// command stream utilities
namespace DivCS {
int getInsLength(unsigned char ins, unsigned char ext=0);
int getCmdLength(unsigned char ext);
int getInsLength(unsigned char ins, unsigned char ext=0, unsigned char* speedDial=NULL);
};
#endif

View file

@ -23,7 +23,216 @@
//#define DISABLE_BLOCK_SEARCH
int DivCS::getInsLength(unsigned char ins, unsigned char ext) {
int DivCS::getCmdLength(unsigned char ext) {
switch (ext) {
case DIV_CMD_SAMPLE_MODE:
case DIV_CMD_SAMPLE_FREQ:
case DIV_CMD_SAMPLE_BANK:
case DIV_CMD_SAMPLE_DIR:
case DIV_CMD_FM_HARD_RESET:
case DIV_CMD_FM_LFO:
case DIV_CMD_FM_LFO_WAVE:
case DIV_CMD_FM_LFO2:
case DIV_CMD_FM_LFO2_WAVE:
case DIV_CMD_FM_FB:
case DIV_CMD_FM_EXTCH:
case DIV_CMD_FM_AM_DEPTH:
case DIV_CMD_FM_PM_DEPTH:
case DIV_CMD_STD_NOISE_FREQ:
case DIV_CMD_STD_NOISE_MODE:
case DIV_CMD_WAVE:
case DIV_CMD_GB_SWEEP_TIME:
case DIV_CMD_GB_SWEEP_DIR:
case DIV_CMD_PCE_LFO_MODE:
case DIV_CMD_PCE_LFO_SPEED:
case DIV_CMD_NES_DMC:
case DIV_CMD_C64_CUTOFF:
case DIV_CMD_C64_RESONANCE:
case DIV_CMD_C64_FILTER_MODE:
case DIV_CMD_C64_RESET_TIME:
case DIV_CMD_C64_RESET_MASK:
case DIV_CMD_C64_FILTER_RESET:
case DIV_CMD_C64_DUTY_RESET:
case DIV_CMD_C64_EXTENDED:
case DIV_CMD_AY_ENVELOPE_SET:
case DIV_CMD_AY_ENVELOPE_LOW:
case DIV_CMD_AY_ENVELOPE_HIGH:
case DIV_CMD_AY_ENVELOPE_SLIDE:
case DIV_CMD_AY_NOISE_MASK_AND:
case DIV_CMD_AY_NOISE_MASK_OR:
case DIV_CMD_AY_AUTO_ENVELOPE:
case DIV_CMD_FDS_MOD_DEPTH:
case DIV_CMD_FDS_MOD_HIGH:
case DIV_CMD_FDS_MOD_LOW:
case DIV_CMD_FDS_MOD_POS:
case DIV_CMD_FDS_MOD_WAVE:
case DIV_CMD_SAA_ENVELOPE:
case DIV_CMD_AMIGA_FILTER:
case DIV_CMD_AMIGA_AM:
case DIV_CMD_AMIGA_PM:
case DIV_CMD_MACRO_OFF:
case DIV_CMD_MACRO_ON:
case DIV_CMD_MACRO_RESTART:
case DIV_CMD_HINT_ARP_TIME:
case DIV_CMD_QSOUND_ECHO_FEEDBACK:
case DIV_CMD_QSOUND_ECHO_LEVEL:
case DIV_CMD_QSOUND_SURROUND:
case DIV_CMD_X1_010_ENVELOPE_SHAPE:
case DIV_CMD_X1_010_ENVELOPE_ENABLE:
case DIV_CMD_X1_010_ENVELOPE_MODE:
case DIV_CMD_X1_010_ENVELOPE_PERIOD:
case DIV_CMD_X1_010_ENVELOPE_SLIDE:
case DIV_CMD_X1_010_AUTO_ENVELOPE:
case DIV_CMD_X1_010_SAMPLE_BANK_SLOT:
case DIV_CMD_WS_SWEEP_TIME:
case DIV_CMD_WS_SWEEP_AMOUNT:
case DIV_CMD_N163_WAVE_POSITION:
case DIV_CMD_N163_WAVE_LENGTH:
case DIV_CMD_N163_WAVE_UNUSED1:
case DIV_CMD_N163_WAVE_UNUSED2:
case DIV_CMD_N163_WAVE_LOADPOS:
case DIV_CMD_N163_WAVE_LOADLEN:
case DIV_CMD_N163_WAVE_UNUSED3:
case DIV_CMD_N163_CHANNEL_LIMIT:
case DIV_CMD_N163_GLOBAL_WAVE_LOAD:
case DIV_CMD_N163_GLOBAL_WAVE_LOADPOS:
case DIV_CMD_N163_UNUSED4:
case DIV_CMD_N163_UNUSED5:
case DIV_CMD_SU_SYNC_PERIOD_LOW:
case DIV_CMD_SU_SYNC_PERIOD_HIGH:
case DIV_CMD_ADPCMA_GLOBAL_VOLUME:
case DIV_CMD_SNES_ECHO:
case DIV_CMD_SNES_PITCH_MOD:
case DIV_CMD_SNES_INVERT:
case DIV_CMD_SNES_GAIN_MODE:
case DIV_CMD_SNES_GAIN:
case DIV_CMD_SNES_ECHO_ENABLE:
case DIV_CMD_SNES_ECHO_DELAY:
case DIV_CMD_SNES_ECHO_VOL_LEFT:
case DIV_CMD_SNES_ECHO_VOL_RIGHT:
case DIV_CMD_SNES_ECHO_FEEDBACK:
case DIV_CMD_NES_ENV_MODE:
case DIV_CMD_NES_LENGTH:
case DIV_CMD_NES_COUNT_MODE:
case DIV_CMD_FM_AM2_DEPTH:
case DIV_CMD_FM_PM2_DEPTH:
case DIV_CMD_ES5506_ENVELOPE_LVRAMP:
case DIV_CMD_ES5506_ENVELOPE_RVRAMP:
case DIV_CMD_ES5506_PAUSE:
case DIV_CMD_ES5506_FILTER_MODE:
case DIV_CMD_SNES_GLOBAL_VOL_LEFT:
case DIV_CMD_SNES_GLOBAL_VOL_RIGHT:
case DIV_CMD_NES_LINEAR_LENGTH:
case DIV_CMD_EXTERNAL:
case DIV_CMD_C64_AD:
case DIV_CMD_C64_SR:
case DIV_CMD_DAVE_HIGH_PASS:
case DIV_CMD_DAVE_RING_MOD:
case DIV_CMD_DAVE_SWAP_COUNTERS:
case DIV_CMD_DAVE_LOW_PASS:
case DIV_CMD_DAVE_CLOCK_DIV:
case DIV_CMD_MINMOD_ECHO:
case DIV_CMD_FDS_MOD_AUTO:
case DIV_CMD_FM_OPMASK:
case DIV_CMD_MULTIPCM_MIX_FM:
case DIV_CMD_MULTIPCM_MIX_PCM:
case DIV_CMD_MULTIPCM_LFO:
case DIV_CMD_MULTIPCM_VIB:
case DIV_CMD_MULTIPCM_AM:
case DIV_CMD_MULTIPCM_AR:
case DIV_CMD_MULTIPCM_D1R:
case DIV_CMD_MULTIPCM_DL:
case DIV_CMD_MULTIPCM_D2R:
case DIV_CMD_MULTIPCM_RC:
case DIV_CMD_MULTIPCM_RR:
case DIV_CMD_MULTIPCM_DAMP:
case DIV_CMD_MULTIPCM_PSEUDO_REVERB:
case DIV_CMD_MULTIPCM_LFO_RESET:
case DIV_CMD_MULTIPCM_LEVEL_DIRECT:
case DIV_CMD_SID3_SPECIAL_WAVE:
case DIV_CMD_SID3_RING_MOD_SRC:
case DIV_CMD_SID3_HARD_SYNC_SRC:
case DIV_CMD_SID3_PHASE_MOD_SRC:
case DIV_CMD_SID3_WAVE_MIX:
case DIV_CMD_SID3_1_BIT_NOISE:
case DIV_CMD_SID3_CHANNEL_INVERSION:
case DIV_CMD_SID3_FILTER_CONNECTION:
case DIV_CMD_SID3_FILTER_MATRIX:
case DIV_CMD_SID3_FILTER_ENABLE:
case DIV_CMD_SID3_PHASE_RESET:
case DIV_CMD_SID3_NOISE_PHASE_RESET:
case DIV_CMD_SID3_ENVELOPE_RESET:
case DIV_CMD_SID3_CUTOFF_SCALING:
case DIV_CMD_SID3_RESONANCE_SCALING:
case DIV_CMD_WS_GLOBAL_SPEAKER_VOLUME:
return 1;
case DIV_CMD_FM_TL:
case DIV_CMD_FM_AM:
case DIV_CMD_FM_AR:
case DIV_CMD_FM_DR:
case DIV_CMD_FM_SL:
case DIV_CMD_FM_D2R:
case DIV_CMD_FM_RR:
case DIV_CMD_FM_DT:
case DIV_CMD_FM_DT2:
case DIV_CMD_FM_RS:
case DIV_CMD_FM_KSR:
case DIV_CMD_FM_VIB:
case DIV_CMD_FM_SUS:
case DIV_CMD_FM_WS:
case DIV_CMD_FM_SSG:
case DIV_CMD_FM_REV:
case DIV_CMD_FM_EG_SHIFT:
case DIV_CMD_FM_MULT:
case DIV_CMD_FM_FINE:
case DIV_CMD_AY_IO_WRITE:
case DIV_CMD_AY_AUTO_PWM:
case DIV_CMD_SURROUND_PANNING:
case DIV_CMD_SU_SWEEP_PERIOD_LOW:
case DIV_CMD_SU_SWEEP_PERIOD_HIGH:
case DIV_CMD_SU_SWEEP_BOUND:
case DIV_CMD_SU_SWEEP_ENABLE:
case DIV_CMD_SNES_ECHO_FIR:
case DIV_CMD_ES5506_FILTER_K1_SLIDE:
case DIV_CMD_ES5506_FILTER_K2_SLIDE:
case DIV_CMD_ES5506_ENVELOPE_K1RAMP:
case DIV_CMD_ES5506_ENVELOPE_K2RAMP:
case DIV_CMD_ESFM_OP_PANNING:
case DIV_CMD_ESFM_OUTLVL:
case DIV_CMD_ESFM_MODIN:
case DIV_CMD_ESFM_ENV_DELAY:
case DIV_CMD_POWERNOISE_COUNTER_LOAD:
case DIV_CMD_POWERNOISE_IO_WRITE:
case DIV_CMD_BIFURCATOR_STATE_LOAD:
case DIV_CMD_BIFURCATOR_PARAMETER:
case DIV_CMD_SID3_LFSR_FEEDBACK_BITS:
case DIV_CMD_SID3_FILTER_DISTORTION:
case DIV_CMD_SID3_FILTER_OUTPUT_VOLUME:
case DIV_CMD_C64_PW_SLIDE:
case DIV_CMD_C64_CUTOFF_SLIDE:
return 2;
case DIV_CMD_C64_FINE_DUTY:
case DIV_CMD_C64_FINE_CUTOFF:
case DIV_CMD_LYNX_LFSR_LOAD:
case DIV_CMD_QSOUND_ECHO_DELAY:
case DIV_CMD_ES5506_ENVELOPE_COUNT:
return 2;
case DIV_CMD_ES5506_FILTER_K1:
case DIV_CMD_ES5506_FILTER_K2:
return 4;
case DIV_CMD_FM_FIXFREQ:
return 2;
case DIV_CMD_NES_SWEEP:
return 2;
case DIV_CMD_SAMPLE_POS:
return 4;
default:
return 0;
}
return 0;
}
int DivCS::getInsLength(unsigned char ins, unsigned char ext, unsigned char* speedDial) {
switch (ins) {
case 0xb8: // ins
case 0xc0: // pre porta
@ -45,14 +254,14 @@ int DivCS::getInsLength(unsigned char ins, unsigned char ext) {
case 0xd4: case 0xd5: case 0xd6: case 0xd7:
case 0xd8: case 0xd9: case 0xda: case 0xdb:
case 0xdc: case 0xdd: case 0xde: case 0xdf:
return 0;
if (speedDial==NULL) return 0;
return 1+getCmdLength(speedDial[ins&15]);
case 0xf0: // opt
return 4;
case 0xf7: { // cmd
case 0xf7: // cmd
// determine length from secondary
if (ext==0) return 0;
return 0;
}
return 2+getCmdLength(ext);
case 0xf8: // call
case 0xfc: // waits
return 3;
@ -97,7 +306,6 @@ void writePackedCommandValues(SafeWriter* w, const DivCommand& c) {
w->writeC((unsigned char)c.cmd+0xb4);
break;
default:
return;
w->writeC(0xf7);
w->writeC(c.cmd);
break;
@ -145,11 +353,12 @@ void writePackedCommandValues(SafeWriter* w, const DivCommand& c) {
case DIV_CMD_SAMPLE_MODE:
case DIV_CMD_SAMPLE_FREQ:
case DIV_CMD_SAMPLE_BANK:
case DIV_CMD_SAMPLE_POS:
case DIV_CMD_SAMPLE_DIR:
case DIV_CMD_FM_HARD_RESET:
case DIV_CMD_FM_LFO:
case DIV_CMD_FM_LFO_WAVE:
case DIV_CMD_FM_LFO2:
case DIV_CMD_FM_LFO2_WAVE:
case DIV_CMD_FM_FB:
case DIV_CMD_FM_EXTCH:
case DIV_CMD_FM_AM_DEPTH:
@ -190,7 +399,97 @@ void writePackedCommandValues(SafeWriter* w, const DivCommand& c) {
case DIV_CMD_MACRO_ON:
case DIV_CMD_MACRO_RESTART:
case DIV_CMD_HINT_ARP_TIME:
w->writeC(1); // length
case DIV_CMD_QSOUND_ECHO_FEEDBACK:
case DIV_CMD_QSOUND_ECHO_LEVEL:
case DIV_CMD_QSOUND_SURROUND:
case DIV_CMD_X1_010_ENVELOPE_SHAPE:
case DIV_CMD_X1_010_ENVELOPE_ENABLE:
case DIV_CMD_X1_010_ENVELOPE_MODE:
case DIV_CMD_X1_010_ENVELOPE_PERIOD:
case DIV_CMD_X1_010_ENVELOPE_SLIDE:
case DIV_CMD_X1_010_AUTO_ENVELOPE:
case DIV_CMD_X1_010_SAMPLE_BANK_SLOT:
case DIV_CMD_WS_SWEEP_TIME:
case DIV_CMD_WS_SWEEP_AMOUNT:
case DIV_CMD_N163_WAVE_POSITION:
case DIV_CMD_N163_WAVE_LENGTH:
case DIV_CMD_N163_WAVE_UNUSED1:
case DIV_CMD_N163_WAVE_UNUSED2:
case DIV_CMD_N163_WAVE_LOADPOS:
case DIV_CMD_N163_WAVE_LOADLEN:
case DIV_CMD_N163_WAVE_UNUSED3:
case DIV_CMD_N163_CHANNEL_LIMIT:
case DIV_CMD_N163_GLOBAL_WAVE_LOAD:
case DIV_CMD_N163_GLOBAL_WAVE_LOADPOS:
case DIV_CMD_N163_UNUSED4:
case DIV_CMD_N163_UNUSED5:
case DIV_CMD_SU_SYNC_PERIOD_LOW:
case DIV_CMD_SU_SYNC_PERIOD_HIGH:
case DIV_CMD_ADPCMA_GLOBAL_VOLUME:
case DIV_CMD_SNES_ECHO:
case DIV_CMD_SNES_PITCH_MOD:
case DIV_CMD_SNES_INVERT:
case DIV_CMD_SNES_GAIN_MODE:
case DIV_CMD_SNES_GAIN:
case DIV_CMD_SNES_ECHO_ENABLE:
case DIV_CMD_SNES_ECHO_DELAY:
case DIV_CMD_SNES_ECHO_VOL_LEFT:
case DIV_CMD_SNES_ECHO_VOL_RIGHT:
case DIV_CMD_SNES_ECHO_FEEDBACK:
case DIV_CMD_NES_ENV_MODE:
case DIV_CMD_NES_LENGTH:
case DIV_CMD_NES_COUNT_MODE:
case DIV_CMD_FM_AM2_DEPTH:
case DIV_CMD_FM_PM2_DEPTH:
case DIV_CMD_ES5506_ENVELOPE_LVRAMP:
case DIV_CMD_ES5506_ENVELOPE_RVRAMP:
case DIV_CMD_ES5506_PAUSE:
case DIV_CMD_ES5506_FILTER_MODE:
case DIV_CMD_SNES_GLOBAL_VOL_LEFT:
case DIV_CMD_SNES_GLOBAL_VOL_RIGHT:
case DIV_CMD_NES_LINEAR_LENGTH:
case DIV_CMD_EXTERNAL:
case DIV_CMD_C64_AD:
case DIV_CMD_C64_SR:
case DIV_CMD_DAVE_HIGH_PASS:
case DIV_CMD_DAVE_RING_MOD:
case DIV_CMD_DAVE_SWAP_COUNTERS:
case DIV_CMD_DAVE_LOW_PASS:
case DIV_CMD_DAVE_CLOCK_DIV:
case DIV_CMD_MINMOD_ECHO:
case DIV_CMD_FDS_MOD_AUTO:
case DIV_CMD_FM_OPMASK:
case DIV_CMD_MULTIPCM_MIX_FM:
case DIV_CMD_MULTIPCM_MIX_PCM:
case DIV_CMD_MULTIPCM_LFO:
case DIV_CMD_MULTIPCM_VIB:
case DIV_CMD_MULTIPCM_AM:
case DIV_CMD_MULTIPCM_AR:
case DIV_CMD_MULTIPCM_D1R:
case DIV_CMD_MULTIPCM_DL:
case DIV_CMD_MULTIPCM_D2R:
case DIV_CMD_MULTIPCM_RC:
case DIV_CMD_MULTIPCM_RR:
case DIV_CMD_MULTIPCM_DAMP:
case DIV_CMD_MULTIPCM_PSEUDO_REVERB:
case DIV_CMD_MULTIPCM_LFO_RESET:
case DIV_CMD_MULTIPCM_LEVEL_DIRECT:
case DIV_CMD_SID3_SPECIAL_WAVE:
case DIV_CMD_SID3_RING_MOD_SRC:
case DIV_CMD_SID3_HARD_SYNC_SRC:
case DIV_CMD_SID3_PHASE_MOD_SRC:
case DIV_CMD_SID3_WAVE_MIX:
case DIV_CMD_SID3_1_BIT_NOISE:
case DIV_CMD_SID3_CHANNEL_INVERSION:
case DIV_CMD_SID3_FILTER_CONNECTION:
case DIV_CMD_SID3_FILTER_MATRIX:
case DIV_CMD_SID3_FILTER_ENABLE:
case DIV_CMD_SID3_PHASE_RESET:
case DIV_CMD_SID3_NOISE_PHASE_RESET:
case DIV_CMD_SID3_ENVELOPE_RESET:
case DIV_CMD_SID3_CUTOFF_SCALING:
case DIV_CMD_SID3_RESONANCE_SCALING:
case DIV_CMD_WS_GLOBAL_SPEAKER_VOLUME:
w->writeC(c.value);
break;
case DIV_CMD_FM_TL:
@ -215,37 +514,66 @@ void writePackedCommandValues(SafeWriter* w, const DivCommand& c) {
case DIV_CMD_AY_IO_WRITE:
case DIV_CMD_AY_AUTO_PWM:
case DIV_CMD_SURROUND_PANNING:
w->writeC(2); // length
case DIV_CMD_SU_SWEEP_PERIOD_LOW:
case DIV_CMD_SU_SWEEP_PERIOD_HIGH:
case DIV_CMD_SU_SWEEP_BOUND:
case DIV_CMD_SU_SWEEP_ENABLE:
case DIV_CMD_SNES_ECHO_FIR:
case DIV_CMD_ES5506_FILTER_K1_SLIDE:
case DIV_CMD_ES5506_FILTER_K2_SLIDE:
case DIV_CMD_ES5506_ENVELOPE_K1RAMP:
case DIV_CMD_ES5506_ENVELOPE_K2RAMP:
case DIV_CMD_ESFM_OP_PANNING:
case DIV_CMD_ESFM_OUTLVL:
case DIV_CMD_ESFM_MODIN:
case DIV_CMD_ESFM_ENV_DELAY:
case DIV_CMD_POWERNOISE_COUNTER_LOAD:
case DIV_CMD_POWERNOISE_IO_WRITE:
case DIV_CMD_BIFURCATOR_STATE_LOAD:
case DIV_CMD_BIFURCATOR_PARAMETER:
case DIV_CMD_SID3_LFSR_FEEDBACK_BITS:
case DIV_CMD_SID3_FILTER_DISTORTION:
case DIV_CMD_SID3_FILTER_OUTPUT_VOLUME:
case DIV_CMD_C64_PW_SLIDE:
case DIV_CMD_C64_CUTOFF_SLIDE:
w->writeC(c.value);
w->writeC(c.value2);
break;
case DIV_CMD_C64_FINE_DUTY:
case DIV_CMD_C64_FINE_CUTOFF:
case DIV_CMD_LYNX_LFSR_LOAD:
w->writeC(2); // length
case DIV_CMD_QSOUND_ECHO_DELAY:
case DIV_CMD_ES5506_ENVELOPE_COUNT:
w->writeS(c.value);
break;
case DIV_CMD_ES5506_FILTER_K1:
case DIV_CMD_ES5506_FILTER_K2:
w->writeS(c.value);
w->writeS(c.value2);
break;
case DIV_CMD_FM_FIXFREQ:
w->writeC(2); // length
w->writeS((c.value<<12)|(c.value2&0x7ff));
break;
case DIV_CMD_NES_SWEEP:
w->writeC(1); // length
w->writeC((c.value?8:0)|(c.value2&0x77));
break;
case DIV_CMD_SAMPLE_POS:
w->writeI(c.value);
break;
default:
logW("unimplemented command %s!",cmdName[c.cmd]);
w->writeC(0); // length
break;
}
}
#define _EXT(b,x,l) (((size_t)((x)+1)<(size_t)(l))?(b[(x)+1]):0)
using namespace DivCS;
void reloc(unsigned char* buf, size_t len, unsigned int sourceAddr, unsigned int destAddr) {
void reloc(unsigned char* buf, size_t len, unsigned int sourceAddr, unsigned int destAddr, unsigned char* speedDial) {
unsigned int delta=destAddr-sourceAddr;
for (size_t i=0; i<len;) {
int insLen=getInsLength(buf[i]);
int insLen=getInsLength(buf[i],_EXT(buf,i,len),speedDial);
if (insLen<1) {
logE("INS %x NOT IMPLEMENTED...",buf[i]);
break;
@ -266,7 +594,7 @@ void reloc(unsigned char* buf, size_t len, unsigned int sourceAddr, unsigned int
}
}
SafeWriter* stripNops(SafeWriter* s) {
SafeWriter* stripNops(SafeWriter* s, unsigned char* speedDial) {
std::unordered_map<unsigned int,unsigned int> addrTable;
SafeWriter* oldStream=s;
unsigned char* buf=oldStream->getFinalBuf();
@ -276,7 +604,7 @@ SafeWriter* stripNops(SafeWriter* s) {
// prepare address map
size_t addr=0;
for (size_t i=0; i<oldStream->size();) {
int insLen=getInsLength(buf[i]);
int insLen=getInsLength(buf[i],_EXT(buf,i,oldStream->size()),speedDial);
if (insLen<1) {
logE("INS %x NOT IMPLEMENTED...",buf[i]);
break;
@ -288,7 +616,7 @@ SafeWriter* stripNops(SafeWriter* s) {
// translate addresses
for (size_t i=0; i<oldStream->size();) {
int insLen=getInsLength(buf[i]);
int insLen=getInsLength(buf[i],_EXT(buf,i,oldStream->size()),speedDial);
if (insLen<1) {
logE("INS %x NOT IMPLEMENTED...",buf[i]);
break;
@ -321,7 +649,7 @@ SafeWriter* stripNops(SafeWriter* s) {
return s;
}
SafeWriter* findSubBlocks(SafeWriter* stream, std::vector<SafeWriter*>& subBlocks) {
SafeWriter* findSubBlocks(SafeWriter* stream, std::vector<SafeWriter*>& subBlocks, unsigned char* speedDial) {
unsigned char* buf=stream->getFinalBuf();
for (size_t groupSize=stream->size()>>1; groupSize>=8; groupSize--) {
@ -333,7 +661,7 @@ SafeWriter* findSubBlocks(SafeWriter* stream, std::vector<SafeWriter*>& subBlock
size_t groupLen=0;
size_t groupInsCount=0;
size_t subBlockID=subBlocks.size();
int insLen=getInsLength(buf[searchPos]);
int insLen=getInsLength(buf[searchPos],_EXT(buf,searchPos,stream->size()),speedDial);
bool haveSub=false;
bool onlyCalls=true;
@ -345,7 +673,7 @@ SafeWriter* findSubBlocks(SafeWriter* stream, std::vector<SafeWriter*>& subBlock
// register this block
for (size_t i=0; i<groupSize && i<stream->size();) {
if (buf[searchPos+i]!=0xf4) onlyCalls=false;
int insLenI=getInsLength(buf[searchPos+i]);
int insLenI=getInsLength(buf[searchPos+i],_EXT(buf,searchPos+i,stream->size()),speedDial);
if (insLenI<1) {
logE("INS %x NOT IMPLEMENTED...",buf[searchPos+i]);
break;
@ -377,7 +705,7 @@ SafeWriter* findSubBlocks(SafeWriter* stream, std::vector<SafeWriter*>& subBlock
// find identical blocks
for (size_t i=searchPos+groupLen; i+groupLen<stream->size();) {
int insLenI=getInsLength(buf[i]);
int insLenI=getInsLength(buf[i],_EXT(buf,i,stream->size()),speedDial);
if (insLenI<1) {
logE("INS %x NOT IMPLEMENTED...",buf[i]);
break;
@ -439,7 +767,7 @@ SafeWriter* findSubBlocks(SafeWriter* stream, std::vector<SafeWriter*>& subBlock
}
}
if (foundSomething) {
stream=stripNops(stream);
stream=stripNops(stream,speedDial);
buf=stream->getFinalBuf();
}
}
@ -591,7 +919,7 @@ SafeWriter* DivEngine::saveCommand() {
unsigned char* buf=chanStream[h]->getFinalBuf();
int delayCount=0;
for (size_t i=0; i<chanStream[h]->size();) {
int insLen=getInsLength(buf[i]);
int insLen=getInsLength(buf[i],_EXT(buf,i,chanStream[h]->size()),sortedCmd);
if (insLen<1) {
logE("INS %x NOT IMPLEMENTED...",buf[i]);
break;
@ -638,7 +966,7 @@ SafeWriter* DivEngine::saveCommand() {
int delayCount=0;
int delayLast=0;
for (size_t i=0; i<chanStream[h]->size();) {
int insLen=getInsLength(buf[i]);
int insLen=getInsLength(buf[i],_EXT(buf,i,chanStream[h]->size()),sortedCmd);
if (insLen<1) {
logE("INS %x NOT IMPLEMENTED...",buf[i]);
break;
@ -690,7 +1018,7 @@ SafeWriter* DivEngine::saveCommand() {
// PASS 2: remove nop's
// this includes modifying call addresses to compensate
for (int h=0; h<chans; h++) {
chanStream[h]=stripNops(chanStream[h]);
chanStream[h]=stripNops(chanStream[h],sortedCmd);
}
#ifndef DISABLE_BLOCK_SEARCH
@ -701,7 +1029,7 @@ SafeWriter* DivEngine::saveCommand() {
// 6 is the minimum size that can be reliably optimized
logI("finding sub-blocks in chan %d",h);
chanStream[h]=findSubBlocks(chanStream[h],subBlocks);
chanStream[h]=findSubBlocks(chanStream[h],subBlocks,sortedCmd);
// find sub-blocks within sub-blocks
size_t subBlocksLast=0;
size_t subBlocksLen=subBlocks.size();
@ -709,7 +1037,7 @@ SafeWriter* DivEngine::saveCommand() {
while (subBlocksLast!=subBlocksLen) {
logI("got %d blocks... starting from %d",(int)subBlocksLen,(int)subBlocksLast);
for (size_t i=subBlocksLast; i<subBlocksLen; i++) {
SafeWriter* newBlock=findSubBlocks(subBlocks[i],subBlocks);
SafeWriter* newBlock=findSubBlocks(subBlocks[i],subBlocks,sortedCmd);
subBlocks[i]=newBlock;
}
subBlocksLast=subBlocksLen;
@ -754,7 +1082,7 @@ SafeWriter* DivEngine::saveCommand() {
// resolve symbols
unsigned char* buf=chanStream[h]->getFinalBuf();
for (size_t j=0; j<chanStream[h]->size();) {
int insLen=getInsLength(buf[j]);
int insLen=getInsLength(buf[j],_EXT(buf,j,chanStream[h]->size()),sortedCmd);
if (insLen<1) {
logE("INS %x NOT IMPLEMENTED...",buf[j]);
break;
@ -783,7 +1111,7 @@ SafeWriter* DivEngine::saveCommand() {
// PASS 4: remove nop's (again)
for (int h=0; h<chans; h++) {
chanStream[h]=stripNops(chanStream[h]);
chanStream[h]=stripNops(chanStream[h],sortedCmd);
}
// PASS 5: optimize command calls
@ -813,7 +1141,7 @@ SafeWriter* DivEngine::saveCommand() {
for (int i=0; i<chans; i++) {
chanStreamOff[i]=w->tell();
logI("- %d: off %x size %ld",i,chanStreamOff[i],chanStream[i]->size());
reloc(chanStream[i]->getFinalBuf(),chanStream[i]->size(),0,w->tell());
reloc(chanStream[i]->getFinalBuf(),chanStream[i]->size(),0,w->tell(),sortedCmd);
w->write(chanStream[i]->getFinalBuf(),chanStream[i]->size());
chanStream[i]->finish();
delete chanStream[i];

View file

@ -598,6 +598,10 @@ void FurnaceGUI::drawMobileControls() {
if (ImGui::Button(_("PatManager"))) {
patManagerOpen=!patManagerOpen;
}
ImGui::SameLine();
if (ImGui::Button(_("CSPlayer"))) {
csPlayerOpen=!csPlayerOpen;
}
ImGui::Separator();