2022-02-15 03:12:20 +00:00
|
|
|
/**
|
|
|
|
* Furnace Tracker - multi-system chiptune tracker
|
2023-01-20 00:18:40 +00:00
|
|
|
* Copyright (C) 2021-2023 tildearrow and contributors
|
2022-02-15 03:12:20 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*/
|
|
|
|
|
2021-05-12 08:58:55 +00:00
|
|
|
#ifndef _DISPATCH_H
|
|
|
|
#define _DISPATCH_H
|
|
|
|
|
2021-12-07 02:12:16 +00:00
|
|
|
#include <stdlib.h>
|
2022-04-30 08:58:30 +00:00
|
|
|
#include <string.h>
|
2022-01-17 04:21:27 +00:00
|
|
|
#include <vector>
|
2022-09-30 01:13:40 +00:00
|
|
|
#include "config.h"
|
2022-12-04 11:06:16 +00:00
|
|
|
#include "chipUtils.h"
|
2021-12-06 10:21:42 +00:00
|
|
|
|
2021-05-16 08:03:23 +00:00
|
|
|
#define ONE_SEMITONE 2200
|
|
|
|
|
2022-01-19 05:01:34 +00:00
|
|
|
#define DIV_NOTE_NULL 0x7fffffff
|
|
|
|
|
2022-01-17 18:29:35 +00:00
|
|
|
#define addWrite(a,v) regWrites.push_back(DivRegWrite(a,v));
|
|
|
|
|
2022-03-07 03:36:32 +00:00
|
|
|
// HOW TO ADD A NEW COMMAND:
|
|
|
|
// add it to this enum. then see playback.cpp.
|
|
|
|
// there is a const char* cmdName[] array, which contains the command
|
|
|
|
// names as strings for the commands (and other debug stuff).
|
|
|
|
//
|
|
|
|
// if you miss it, the program will crash or misbehave at some point.
|
2022-04-26 20:24:45 +00:00
|
|
|
//
|
|
|
|
// the comments are: (arg1, arg2) -> val
|
|
|
|
// not all commands have a return value
|
2021-05-11 20:08:08 +00:00
|
|
|
enum DivDispatchCmds {
|
2022-04-26 20:24:45 +00:00
|
|
|
DIV_CMD_NOTE_ON=0, // (note)
|
2021-05-11 20:08:08 +00:00
|
|
|
DIV_CMD_NOTE_OFF,
|
2022-02-08 08:50:42 +00:00
|
|
|
DIV_CMD_NOTE_OFF_ENV,
|
|
|
|
DIV_CMD_ENV_RELEASE,
|
2022-04-26 20:24:45 +00:00
|
|
|
DIV_CMD_INSTRUMENT, // (ins, force)
|
|
|
|
DIV_CMD_VOLUME, // (vol)
|
|
|
|
DIV_CMD_GET_VOLUME, // () -> vol
|
|
|
|
DIV_CMD_GET_VOLMAX, // () -> volMax
|
|
|
|
DIV_CMD_NOTE_PORTA, // (target, speed) -> 2 if target reached
|
|
|
|
DIV_CMD_PITCH, // (pitch)
|
2022-04-30 04:41:14 +00:00
|
|
|
DIV_CMD_PANNING, // (left, right)
|
2022-04-26 20:24:45 +00:00
|
|
|
DIV_CMD_LEGATO, // (note)
|
|
|
|
DIV_CMD_PRE_PORTA, // (inPorta, isPortaOrSlide)
|
|
|
|
DIV_CMD_PRE_NOTE, // used in C64 (note)
|
|
|
|
|
2022-08-03 22:21:47 +00:00
|
|
|
// these will be used in ROM export.
|
|
|
|
// do NOT implement!
|
|
|
|
DIV_CMD_HINT_VIBRATO, // (speed, depth)
|
2022-08-04 20:14:29 +00:00
|
|
|
DIV_CMD_HINT_VIBRATO_RANGE, // (range)
|
2022-08-03 22:21:47 +00:00
|
|
|
DIV_CMD_HINT_VIBRATO_SHAPE, // (shape)
|
|
|
|
DIV_CMD_HINT_PITCH, // (pitch)
|
|
|
|
DIV_CMD_HINT_ARPEGGIO, // (note1, note2)
|
2022-08-04 20:14:29 +00:00
|
|
|
DIV_CMD_HINT_VOLUME, // (vol)
|
2022-08-03 22:21:47 +00:00
|
|
|
DIV_CMD_HINT_VOL_SLIDE, // (amount, oneTick)
|
2022-08-04 20:14:29 +00:00
|
|
|
DIV_CMD_HINT_PORTA, // (target, speed)
|
|
|
|
DIV_CMD_HINT_LEGATO, // (note)
|
2022-08-03 22:21:47 +00:00
|
|
|
|
2022-04-26 20:24:45 +00:00
|
|
|
DIV_CMD_SAMPLE_MODE, // (enabled)
|
|
|
|
DIV_CMD_SAMPLE_FREQ, // (frequency)
|
|
|
|
DIV_CMD_SAMPLE_BANK, // (bank)
|
|
|
|
DIV_CMD_SAMPLE_POS, // (pos)
|
2022-05-27 07:47:44 +00:00
|
|
|
DIV_CMD_SAMPLE_DIR, // (direction)
|
2022-04-26 20:24:45 +00:00
|
|
|
|
|
|
|
DIV_CMD_FM_HARD_RESET, // (enabled)
|
|
|
|
DIV_CMD_FM_LFO, // (speed)
|
|
|
|
DIV_CMD_FM_LFO_WAVE, // (waveform)
|
|
|
|
DIV_CMD_FM_TL, // (op, value)
|
2022-05-02 08:52:45 +00:00
|
|
|
DIV_CMD_FM_AM, // (op, value)
|
2022-04-26 20:24:45 +00:00
|
|
|
DIV_CMD_FM_AR, // (op, value)
|
2022-05-02 08:52:45 +00:00
|
|
|
DIV_CMD_FM_DR, // (op, value)
|
|
|
|
DIV_CMD_FM_SL, // (op, value)
|
|
|
|
DIV_CMD_FM_D2R, // (op, value)
|
|
|
|
DIV_CMD_FM_RR, // (op, value)
|
|
|
|
DIV_CMD_FM_DT, // (op, value)
|
|
|
|
DIV_CMD_FM_DT2, // (op, value)
|
|
|
|
DIV_CMD_FM_RS, // (op, value)
|
|
|
|
DIV_CMD_FM_KSR, // (op, value)
|
|
|
|
DIV_CMD_FM_VIB, // (op, value)
|
|
|
|
DIV_CMD_FM_SUS, // (op, value)
|
|
|
|
DIV_CMD_FM_WS, // (op, value)
|
|
|
|
DIV_CMD_FM_SSG, // (op, value)
|
2022-05-03 22:37:17 +00:00
|
|
|
DIV_CMD_FM_REV, // (op, value)
|
|
|
|
DIV_CMD_FM_EG_SHIFT, // (op, value)
|
2022-04-26 20:24:45 +00:00
|
|
|
DIV_CMD_FM_FB, // (value)
|
|
|
|
DIV_CMD_FM_MULT, // (op, value)
|
2022-05-02 08:52:45 +00:00
|
|
|
DIV_CMD_FM_FINE, // (op, value)
|
|
|
|
DIV_CMD_FM_FIXFREQ, // (op, value)
|
2022-04-26 20:24:45 +00:00
|
|
|
DIV_CMD_FM_EXTCH, // (enabled)
|
|
|
|
DIV_CMD_FM_AM_DEPTH, // (depth)
|
|
|
|
DIV_CMD_FM_PM_DEPTH, // (depth)
|
|
|
|
|
2023-02-03 22:00:15 +00:00
|
|
|
DIV_CMD_FM_LFO2, // (speed)
|
|
|
|
DIV_CMD_FM_LFO2_WAVE, // (waveform)
|
2021-05-15 08:13:21 +00:00
|
|
|
|
2022-04-26 20:24:45 +00:00
|
|
|
DIV_CMD_STD_NOISE_FREQ, // (freq)
|
|
|
|
DIV_CMD_STD_NOISE_MODE, // (mode)
|
2021-05-19 07:05:24 +00:00
|
|
|
|
2022-04-26 20:24:45 +00:00
|
|
|
DIV_CMD_WAVE, // (waveform)
|
2021-05-28 05:36:25 +00:00
|
|
|
|
2022-04-26 20:24:45 +00:00
|
|
|
DIV_CMD_GB_SWEEP_TIME, // (time)
|
|
|
|
DIV_CMD_GB_SWEEP_DIR, // (direction)
|
2021-05-28 05:36:25 +00:00
|
|
|
|
2022-04-26 20:24:45 +00:00
|
|
|
DIV_CMD_PCE_LFO_MODE, // (mode)
|
|
|
|
DIV_CMD_PCE_LFO_SPEED, // (speed)
|
2021-06-09 06:08:42 +00:00
|
|
|
|
2022-04-26 20:24:45 +00:00
|
|
|
DIV_CMD_NES_SWEEP, // (direction, value)
|
2022-04-29 05:18:51 +00:00
|
|
|
DIV_CMD_NES_DMC, // (value)
|
2022-02-01 23:28:48 +00:00
|
|
|
|
2022-04-26 20:24:45 +00:00
|
|
|
DIV_CMD_C64_CUTOFF, // (value)
|
|
|
|
DIV_CMD_C64_RESONANCE, // (value)
|
|
|
|
DIV_CMD_C64_FILTER_MODE, // (value)
|
|
|
|
DIV_CMD_C64_RESET_TIME, // (value)
|
|
|
|
DIV_CMD_C64_RESET_MASK, // (mask)
|
|
|
|
DIV_CMD_C64_FILTER_RESET, // (value)
|
|
|
|
DIV_CMD_C64_DUTY_RESET, // (value)
|
|
|
|
DIV_CMD_C64_EXTENDED, // (value)
|
|
|
|
DIV_CMD_C64_FINE_DUTY, // (value)
|
|
|
|
DIV_CMD_C64_FINE_CUTOFF, // (value)
|
2021-12-07 06:23:57 +00:00
|
|
|
|
2021-12-09 22:06:28 +00:00
|
|
|
DIV_CMD_AY_ENVELOPE_SET,
|
|
|
|
DIV_CMD_AY_ENVELOPE_LOW,
|
|
|
|
DIV_CMD_AY_ENVELOPE_HIGH,
|
2022-01-11 23:38:26 +00:00
|
|
|
DIV_CMD_AY_ENVELOPE_SLIDE,
|
2022-04-26 20:24:45 +00:00
|
|
|
DIV_CMD_AY_NOISE_MASK_AND, // (value)
|
|
|
|
DIV_CMD_AY_NOISE_MASK_OR, // (value)
|
|
|
|
DIV_CMD_AY_AUTO_ENVELOPE, // (value)
|
|
|
|
DIV_CMD_AY_IO_WRITE, // (port, value)
|
2022-03-27 01:55:43 +00:00
|
|
|
DIV_CMD_AY_AUTO_PWM,
|
2021-12-09 22:06:28 +00:00
|
|
|
|
2022-04-04 03:37:16 +00:00
|
|
|
DIV_CMD_FDS_MOD_DEPTH,
|
|
|
|
DIV_CMD_FDS_MOD_HIGH,
|
|
|
|
DIV_CMD_FDS_MOD_LOW,
|
|
|
|
DIV_CMD_FDS_MOD_POS,
|
|
|
|
DIV_CMD_FDS_MOD_WAVE,
|
|
|
|
|
2022-04-26 20:24:45 +00:00
|
|
|
DIV_CMD_SAA_ENVELOPE, // (value)
|
2022-01-15 04:26:22 +00:00
|
|
|
|
2022-04-26 20:24:45 +00:00
|
|
|
DIV_CMD_AMIGA_FILTER, // (enabled)
|
|
|
|
DIV_CMD_AMIGA_AM, // (enabled)
|
|
|
|
DIV_CMD_AMIGA_PM, // (enabled)
|
2022-03-27 04:39:20 +00:00
|
|
|
|
2022-04-26 20:24:45 +00:00
|
|
|
DIV_CMD_LYNX_LFSR_LOAD, // (value)
|
2022-02-22 23:21:57 +00:00
|
|
|
|
2022-02-22 09:01:57 +00:00
|
|
|
DIV_CMD_QSOUND_ECHO_FEEDBACK,
|
2022-02-22 20:16:46 +00:00
|
|
|
DIV_CMD_QSOUND_ECHO_DELAY,
|
2022-02-22 09:01:57 +00:00
|
|
|
DIV_CMD_QSOUND_ECHO_LEVEL,
|
2022-04-29 04:58:11 +00:00
|
|
|
DIV_CMD_QSOUND_SURROUND,
|
2022-02-21 11:41:06 +00:00
|
|
|
|
2022-03-06 17:31:03 +00:00
|
|
|
DIV_CMD_X1_010_ENVELOPE_SHAPE,
|
|
|
|
DIV_CMD_X1_010_ENVELOPE_ENABLE,
|
|
|
|
DIV_CMD_X1_010_ENVELOPE_MODE,
|
|
|
|
DIV_CMD_X1_010_ENVELOPE_PERIOD,
|
|
|
|
DIV_CMD_X1_010_ENVELOPE_SLIDE,
|
|
|
|
DIV_CMD_X1_010_AUTO_ENVELOPE,
|
Prepare for split sample chip instrument
(MSM6258, MSM6295, QSound, Sega PCM, ADPCM-A, ADPCM-B, YMZ280B, RF5C68)
Instrument color and icons are placeholder.
different volume range, hard panned/soft panned and/or independent volume per output, chip-dependent features (global volume, echo, etc)
Allow use sample in instrument tab for chip with sample support
Prepare to support X1-010 Seta 2 style bankswitch behavior
Prepare to support AY89x0 PCM DAC
Support volume for PCE sample (DAC)
Fix Lynx, Y8950 sample pitch matches to sample preview
Support PCM DAC with backward and pingpong loop mode
Reduce some codes
Add Sega PCM, AY89x0, QSound, PCM DAC, Lynx per-channel debug support
2022-08-27 07:27:36 +00:00
|
|
|
DIV_CMD_X1_010_SAMPLE_BANK_SLOT,
|
2022-03-06 17:31:03 +00:00
|
|
|
|
2022-03-06 16:13:47 +00:00
|
|
|
DIV_CMD_WS_SWEEP_TIME,
|
|
|
|
DIV_CMD_WS_SWEEP_AMOUNT,
|
|
|
|
|
2022-03-22 16:48:45 +00:00
|
|
|
DIV_CMD_N163_WAVE_POSITION,
|
|
|
|
DIV_CMD_N163_WAVE_LENGTH,
|
2023-07-22 00:54:35 +00:00
|
|
|
DIV_CMD_N163_WAVE_UNUSED1,
|
|
|
|
DIV_CMD_N163_WAVE_UNUSED2,
|
2022-03-22 16:48:45 +00:00
|
|
|
DIV_CMD_N163_WAVE_LOADPOS,
|
|
|
|
DIV_CMD_N163_WAVE_LOADLEN,
|
2023-07-22 00:54:35 +00:00
|
|
|
DIV_CMD_N163_WAVE_UNUSED3,
|
2022-03-22 16:48:45 +00:00
|
|
|
DIV_CMD_N163_CHANNEL_LIMIT,
|
|
|
|
DIV_CMD_N163_GLOBAL_WAVE_LOAD,
|
|
|
|
DIV_CMD_N163_GLOBAL_WAVE_LOADPOS,
|
2023-07-22 00:54:35 +00:00
|
|
|
DIV_CMD_N163_UNUSED4,
|
|
|
|
DIV_CMD_N163_UNUSED5,
|
2022-03-22 16:48:45 +00:00
|
|
|
|
2022-05-19 09:36:26 +00:00
|
|
|
DIV_CMD_SU_SWEEP_PERIOD_LOW, // (which, val)
|
|
|
|
DIV_CMD_SU_SWEEP_PERIOD_HIGH, // (which, val)
|
|
|
|
DIV_CMD_SU_SWEEP_BOUND, // (which, val)
|
|
|
|
DIV_CMD_SU_SWEEP_ENABLE, // (which, val)
|
|
|
|
DIV_CMD_SU_SYNC_PERIOD_LOW,
|
|
|
|
DIV_CMD_SU_SYNC_PERIOD_HIGH,
|
|
|
|
|
Prepare for split sample chip instrument
(MSM6258, MSM6295, QSound, Sega PCM, ADPCM-A, ADPCM-B, YMZ280B, RF5C68)
Instrument color and icons are placeholder.
different volume range, hard panned/soft panned and/or independent volume per output, chip-dependent features (global volume, echo, etc)
Allow use sample in instrument tab for chip with sample support
Prepare to support X1-010 Seta 2 style bankswitch behavior
Prepare to support AY89x0 PCM DAC
Support volume for PCE sample (DAC)
Fix Lynx, Y8950 sample pitch matches to sample preview
Support PCM DAC with backward and pingpong loop mode
Reduce some codes
Add Sega PCM, AY89x0, QSound, PCM DAC, Lynx per-channel debug support
2022-08-27 07:27:36 +00:00
|
|
|
DIV_CMD_ADPCMA_GLOBAL_VOLUME,
|
|
|
|
|
2022-09-25 09:02:06 +00:00
|
|
|
DIV_CMD_SNES_ECHO,
|
|
|
|
DIV_CMD_SNES_PITCH_MOD,
|
|
|
|
DIV_CMD_SNES_INVERT,
|
|
|
|
DIV_CMD_SNES_GAIN_MODE,
|
|
|
|
DIV_CMD_SNES_GAIN,
|
|
|
|
DIV_CMD_SNES_ECHO_ENABLE,
|
|
|
|
DIV_CMD_SNES_ECHO_DELAY,
|
|
|
|
DIV_CMD_SNES_ECHO_VOL_LEFT,
|
|
|
|
DIV_CMD_SNES_ECHO_VOL_RIGHT,
|
|
|
|
DIV_CMD_SNES_ECHO_FEEDBACK,
|
|
|
|
DIV_CMD_SNES_ECHO_FIR,
|
|
|
|
|
2022-10-25 05:43:03 +00:00
|
|
|
DIV_CMD_NES_ENV_MODE,
|
|
|
|
DIV_CMD_NES_LENGTH,
|
|
|
|
DIV_CMD_NES_COUNT_MODE,
|
|
|
|
|
2022-12-17 05:09:56 +00:00
|
|
|
DIV_CMD_MACRO_OFF, // (which)
|
|
|
|
DIV_CMD_MACRO_ON, // (which)
|
|
|
|
|
2023-02-05 01:04:31 +00:00
|
|
|
DIV_CMD_SURROUND_PANNING, // (out, val)
|
|
|
|
|
|
|
|
DIV_CMD_FM_AM2_DEPTH, // (depth)
|
|
|
|
DIV_CMD_FM_PM2_DEPTH, // (depth)
|
|
|
|
|
2022-12-25 09:51:23 +00:00
|
|
|
DIV_CMD_ES5506_FILTER_MODE, // (value)
|
|
|
|
DIV_CMD_ES5506_FILTER_K1, // (value, mask)
|
|
|
|
DIV_CMD_ES5506_FILTER_K2, // (value, mask)
|
|
|
|
DIV_CMD_ES5506_FILTER_K1_SLIDE, // (value, negative)
|
|
|
|
DIV_CMD_ES5506_FILTER_K2_SLIDE, // (value, negative)
|
|
|
|
DIV_CMD_ES5506_ENVELOPE_COUNT, // (count)
|
|
|
|
DIV_CMD_ES5506_ENVELOPE_LVRAMP, // (ramp)
|
|
|
|
DIV_CMD_ES5506_ENVELOPE_RVRAMP, // (ramp)
|
|
|
|
DIV_CMD_ES5506_ENVELOPE_K1RAMP, // (ramp, slowdown)
|
|
|
|
DIV_CMD_ES5506_ENVELOPE_K2RAMP, // (ramp, slowdown)
|
|
|
|
DIV_CMD_ES5506_PAUSE, // (value)
|
|
|
|
|
2023-03-27 08:29:43 +00:00
|
|
|
DIV_CMD_HINT_ARP_TIME, // (value)
|
|
|
|
|
2023-05-04 21:49:47 +00:00
|
|
|
DIV_CMD_SNES_GLOBAL_VOL_LEFT,
|
|
|
|
DIV_CMD_SNES_GLOBAL_VOL_RIGHT,
|
|
|
|
|
2023-05-05 06:10:03 +00:00
|
|
|
DIV_CMD_NES_LINEAR_LENGTH,
|
|
|
|
|
2023-07-05 22:29:11 +00:00
|
|
|
DIV_CMD_EXTERNAL, // (value)
|
2023-07-05 22:07:44 +00:00
|
|
|
|
2022-04-26 20:24:45 +00:00
|
|
|
DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol
|
2021-05-28 05:36:25 +00:00
|
|
|
|
2021-05-19 07:05:24 +00:00
|
|
|
DIV_CMD_MAX
|
2021-05-11 20:08:08 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct DivCommand {
|
|
|
|
DivDispatchCmds cmd;
|
2022-01-08 21:03:32 +00:00
|
|
|
unsigned char chan, dis;
|
2021-05-14 19:16:48 +00:00
|
|
|
int value, value2;
|
|
|
|
DivCommand(DivDispatchCmds c, unsigned char ch, int val, int val2):
|
2021-05-12 10:22:01 +00:00
|
|
|
cmd(c),
|
|
|
|
chan(ch),
|
2022-01-08 21:03:32 +00:00
|
|
|
dis(ch),
|
2021-05-14 19:16:48 +00:00
|
|
|
value(val),
|
|
|
|
value2(val2) {}
|
|
|
|
DivCommand(DivDispatchCmds c, unsigned char ch, int val):
|
|
|
|
cmd(c),
|
|
|
|
chan(ch),
|
2022-01-08 21:03:32 +00:00
|
|
|
dis(ch),
|
2021-05-14 19:16:48 +00:00
|
|
|
value(val),
|
|
|
|
value2(0) {}
|
2021-05-12 10:22:01 +00:00
|
|
|
DivCommand(DivDispatchCmds c, unsigned char ch):
|
|
|
|
cmd(c),
|
|
|
|
chan(ch),
|
2022-01-08 21:03:32 +00:00
|
|
|
dis(ch),
|
2021-05-14 19:16:48 +00:00
|
|
|
value(0),
|
|
|
|
value2(0) {}
|
2021-05-11 20:08:08 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct DivDelayedCommand {
|
|
|
|
int ticks;
|
|
|
|
DivCommand cmd;
|
|
|
|
};
|
|
|
|
|
2022-01-17 04:21:27 +00:00
|
|
|
struct DivRegWrite {
|
|
|
|
/**
|
2022-01-24 06:01:08 +00:00
|
|
|
* an address of 0xffffxx00 indicates a Furnace specific command.
|
2022-01-17 04:21:27 +00:00
|
|
|
* the following addresses are available:
|
2022-01-24 06:01:08 +00:00
|
|
|
* - 0xffffxx00: start sample playback
|
|
|
|
* - xx is the instance ID
|
2022-01-17 04:21:27 +00:00
|
|
|
* - data is the sample number
|
2022-01-24 06:01:08 +00:00
|
|
|
* - 0xffffxx01: set sample rate
|
|
|
|
* - xx is the instance ID
|
|
|
|
* - data is the sample rate
|
|
|
|
* - 0xffffxx02: stop sample playback
|
|
|
|
* - xx is the instance ID
|
2022-05-27 07:47:44 +00:00
|
|
|
* - 0xffffxx03: set sample playback direction
|
|
|
|
* - x is the instance ID
|
2023-06-22 08:24:39 +00:00
|
|
|
* - 0xffffxx04: switch sample bank
|
|
|
|
* - for use in VGM export
|
2023-07-09 20:12:45 +00:00
|
|
|
* - 0xffffxx05: set sample position
|
|
|
|
* - xx is the instance ID
|
|
|
|
* - data is the sample position
|
2022-01-24 06:01:08 +00:00
|
|
|
* - 0xffffffff: reset
|
2022-01-17 04:21:27 +00:00
|
|
|
*/
|
|
|
|
unsigned int addr;
|
2023-03-14 06:27:45 +00:00
|
|
|
unsigned int val;
|
2023-07-13 09:09:20 +00:00
|
|
|
DivRegWrite():
|
|
|
|
addr(0), val(0) {}
|
2023-03-14 06:27:45 +00:00
|
|
|
DivRegWrite(unsigned int a, unsigned int v):
|
2022-01-17 18:29:35 +00:00
|
|
|
addr(a), val(v) {}
|
2022-01-17 04:21:27 +00:00
|
|
|
};
|
|
|
|
|
2022-10-17 02:35:25 +00:00
|
|
|
struct DivDelayedWrite {
|
|
|
|
int time;
|
|
|
|
DivRegWrite write;
|
2023-03-14 06:27:45 +00:00
|
|
|
DivDelayedWrite(int t, unsigned int a, unsigned int v):
|
2022-10-17 19:25:30 +00:00
|
|
|
time(t),
|
|
|
|
write(a,v) {}
|
2022-10-17 02:35:25 +00:00
|
|
|
};
|
|
|
|
|
2023-03-19 08:12:08 +00:00
|
|
|
struct DivSamplePos {
|
|
|
|
int sample, pos, freq;
|
|
|
|
DivSamplePos(int s, int p, int f):
|
|
|
|
sample(s),
|
|
|
|
pos(p),
|
|
|
|
freq(f) {}
|
|
|
|
DivSamplePos():
|
|
|
|
sample(-1),
|
|
|
|
pos(0),
|
|
|
|
freq(0) {}
|
|
|
|
};
|
|
|
|
|
2022-04-30 08:58:30 +00:00
|
|
|
struct DivDispatchOscBuffer {
|
2022-05-03 01:20:20 +00:00
|
|
|
bool follow;
|
2022-04-30 08:58:30 +00:00
|
|
|
unsigned int rate;
|
|
|
|
unsigned short needle;
|
2022-05-01 23:29:16 +00:00
|
|
|
unsigned short readNeedle;
|
2022-05-03 01:20:20 +00:00
|
|
|
unsigned short followNeedle;
|
2022-04-30 08:58:30 +00:00
|
|
|
short data[65536];
|
|
|
|
|
|
|
|
DivDispatchOscBuffer():
|
2022-05-03 01:20:20 +00:00
|
|
|
follow(true),
|
2022-04-30 08:58:30 +00:00
|
|
|
rate(65536),
|
2022-05-01 23:29:16 +00:00
|
|
|
needle(0),
|
2022-05-03 01:20:20 +00:00
|
|
|
readNeedle(0),
|
|
|
|
followNeedle(0) {
|
2022-04-30 08:58:30 +00:00
|
|
|
memset(data,0,65536*sizeof(short));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-05-12 08:58:55 +00:00
|
|
|
class DivEngine;
|
2022-04-26 20:24:45 +00:00
|
|
|
class DivMacroInt;
|
2021-05-12 08:58:55 +00:00
|
|
|
|
2021-05-11 20:08:08 +00:00
|
|
|
class DivDispatch {
|
2021-05-12 08:58:55 +00:00
|
|
|
protected:
|
|
|
|
DivEngine* parent;
|
2022-01-17 04:21:27 +00:00
|
|
|
std::vector<DivRegWrite> regWrites;
|
2021-12-21 06:29:07 +00:00
|
|
|
/**
|
2022-01-17 04:21:27 +00:00
|
|
|
* please honor these variables if needed.
|
2021-12-21 06:29:07 +00:00
|
|
|
*/
|
2022-01-17 04:21:27 +00:00
|
|
|
bool skipRegisterWrites, dumpWrites;
|
2021-05-11 20:08:08 +00:00
|
|
|
public:
|
2021-05-12 08:58:55 +00:00
|
|
|
/**
|
|
|
|
* the rate the samples are provided.
|
|
|
|
* the engine shall resample to the output rate.
|
2022-04-26 20:24:45 +00:00
|
|
|
* you have to initialize this one during init() or setFlags().
|
2021-05-12 08:58:55 +00:00
|
|
|
*/
|
|
|
|
int rate;
|
2022-01-28 05:55:51 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* the actual chip's clock.
|
2022-04-26 20:24:45 +00:00
|
|
|
* you have to initialize this one during init() or setFlags().
|
2022-01-28 05:55:51 +00:00
|
|
|
*/
|
|
|
|
int chipClock;
|
2021-12-18 08:25:42 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* fill a buffer with sound data.
|
2023-01-02 00:46:08 +00:00
|
|
|
* @param buf pointers to output buffers.
|
2021-12-18 08:25:42 +00:00
|
|
|
* @param len the amount of samples to fill.
|
|
|
|
*/
|
2023-01-02 00:46:08 +00:00
|
|
|
virtual void acquire(short** buf, size_t len);
|
2021-12-18 08:25:42 +00:00
|
|
|
|
2022-10-17 02:35:25 +00:00
|
|
|
/**
|
|
|
|
* fill a write stream with data (e.g. for software-mixed PCM).
|
|
|
|
* @param stream the write stream.
|
|
|
|
* @param rate stream rate (e.g. 44100 for VGM).
|
|
|
|
* @param len number of samples.
|
|
|
|
*/
|
2022-10-17 09:17:00 +00:00
|
|
|
virtual void fillStream(std::vector<DivDelayedWrite>& stream, int sRate, size_t len);
|
2022-10-17 02:35:25 +00:00
|
|
|
|
2021-12-18 08:25:42 +00:00
|
|
|
/**
|
|
|
|
* send a command to this dispatch.
|
|
|
|
* @param c a DivCommand.
|
|
|
|
* @return a return value which varies depending on the command.
|
|
|
|
*/
|
2021-05-11 20:08:08 +00:00
|
|
|
virtual int dispatch(DivCommand c);
|
2021-12-18 08:25:42 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* reset the state of this dispatch.
|
|
|
|
*/
|
2021-12-11 08:34:43 +00:00
|
|
|
virtual void reset();
|
2021-12-18 08:25:42 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* ticks this dispatch.
|
2022-04-15 20:01:11 +00:00
|
|
|
* @param sysTick whether the engine has ticked (if not then this may be a sub-tick used in low-latency mode).
|
2021-12-18 08:25:42 +00:00
|
|
|
*/
|
2022-04-15 20:01:11 +00:00
|
|
|
virtual void tick(bool sysTick=true);
|
2021-05-11 20:08:08 +00:00
|
|
|
|
2022-01-27 05:29:16 +00:00
|
|
|
/**
|
|
|
|
* get the state of a channel.
|
2023-03-19 08:12:08 +00:00
|
|
|
* @param chan the channel.
|
2022-01-27 05:29:16 +00:00
|
|
|
* @return a pointer, or NULL.
|
|
|
|
*/
|
|
|
|
virtual void* getChanState(int chan);
|
2022-04-26 20:24:45 +00:00
|
|
|
|
|
|
|
/**
|
2023-03-19 08:12:08 +00:00
|
|
|
* get the DivMacroInt of a channel.
|
|
|
|
* @param chan the channel.
|
2022-04-26 20:24:45 +00:00
|
|
|
* @return a pointer, or NULL.
|
|
|
|
*/
|
|
|
|
virtual DivMacroInt* getChanMacroInt(int chan);
|
2022-04-30 08:58:30 +00:00
|
|
|
|
2023-03-19 08:12:08 +00:00
|
|
|
/**
|
|
|
|
* get currently playing sample (and its position).
|
|
|
|
* @param chan the channel.
|
|
|
|
* @return a DivSamplePos. if sample is -1 then nothing is playing or the
|
|
|
|
* channel doesn't play samples.
|
|
|
|
*/
|
|
|
|
virtual DivSamplePos getSamplePos(int chan);
|
|
|
|
|
2022-04-30 08:58:30 +00:00
|
|
|
/**
|
|
|
|
* get an oscilloscope buffer for a channel.
|
2023-03-19 08:12:08 +00:00
|
|
|
* @param chan the channel.
|
2022-04-30 08:58:30 +00:00
|
|
|
* @return a pointer to a DivDispatchOscBuffer, or NULL if not supported.
|
|
|
|
*/
|
|
|
|
virtual DivDispatchOscBuffer* getOscBuffer(int chan);
|
2022-02-22 03:31:27 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* get the register pool of this dispatch.
|
|
|
|
* @return a pointer, or NULL.
|
|
|
|
*/
|
|
|
|
virtual unsigned char* getRegisterPool();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get the size of the register pool of this dispatch.
|
|
|
|
* @return the size.
|
|
|
|
*/
|
|
|
|
virtual int getRegisterPoolSize();
|
2022-01-27 05:29:16 +00:00
|
|
|
|
2022-02-22 09:01:57 +00:00
|
|
|
/**
|
|
|
|
* get the bit depth of the register pool of this dispatch.
|
2022-02-23 03:13:17 +00:00
|
|
|
* If the result is 16, it should be casted to unsigned short.
|
2022-02-22 09:01:57 +00:00
|
|
|
* @return the depth. Default value is 8
|
|
|
|
*/
|
|
|
|
virtual int getRegisterPoolDepth();
|
|
|
|
|
2021-12-18 08:25:42 +00:00
|
|
|
/**
|
2022-02-22 03:31:27 +00:00
|
|
|
* get this dispatch's state. DO NOT IMPLEMENT YET.
|
2021-12-18 08:25:42 +00:00
|
|
|
* @return a pointer to the dispatch's state. must be deallocated manually!
|
|
|
|
*/
|
|
|
|
virtual void* getState();
|
|
|
|
|
|
|
|
/**
|
2022-02-22 03:31:27 +00:00
|
|
|
* set this dispatch's state. DO NOT IMPLEMENT YET.
|
2021-12-18 08:25:42 +00:00
|
|
|
* @param state a pointer to a state pertaining to this dispatch,
|
|
|
|
* or NULL if this dispatch does not support state saves.
|
|
|
|
*/
|
|
|
|
virtual void setState(void* state);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* mute a channel.
|
|
|
|
* @param ch the channel to mute.
|
|
|
|
* @param mute whether to mute or unmute.
|
|
|
|
*/
|
|
|
|
virtual void muteChannel(int ch, bool mute);
|
|
|
|
|
|
|
|
/**
|
2023-01-02 00:46:08 +00:00
|
|
|
* get the number of outputs this dispatch provides.
|
|
|
|
* @return number of outputs (usually 1 or 2 but may be more). SHALL NOT be less than one.
|
2021-12-18 08:25:42 +00:00
|
|
|
*/
|
2023-01-02 00:46:08 +00:00
|
|
|
virtual int getOutputCount();
|
2021-12-18 08:25:42 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* test whether sending a key off command to a channel should reset arp too.
|
|
|
|
* @param ch the channel in question.
|
|
|
|
* @return whether it does.
|
|
|
|
*/
|
2021-12-08 05:33:00 +00:00
|
|
|
virtual bool keyOffAffectsArp(int ch);
|
2021-12-18 08:25:42 +00:00
|
|
|
|
2021-12-29 07:08:50 +00:00
|
|
|
/**
|
|
|
|
* test whether sending a key off command to a channel should reset slides too.
|
|
|
|
* @param ch the channel in question.
|
|
|
|
* @return whether it does.
|
|
|
|
*/
|
|
|
|
virtual bool keyOffAffectsPorta(int ch);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get the lowest note in a portamento.
|
|
|
|
* @param ch the channel in question.
|
|
|
|
* @return the lowest note.
|
|
|
|
*/
|
|
|
|
virtual int getPortaFloor(int ch);
|
|
|
|
|
2022-04-09 23:25:25 +00:00
|
|
|
/**
|
|
|
|
* get the required amplification level of this dispatch's output.
|
|
|
|
* @return the amplification level.
|
|
|
|
*/
|
|
|
|
virtual float getPostAmp();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* check whether DC offset correction is required.
|
|
|
|
* @return truth.
|
|
|
|
*/
|
|
|
|
virtual bool getDCOffRequired();
|
|
|
|
|
2022-01-20 18:48:20 +00:00
|
|
|
/**
|
2022-08-03 21:21:30 +00:00
|
|
|
* check whether PRE_NOTE command is desired.
|
|
|
|
* @return truth.
|
2022-01-20 18:48:20 +00:00
|
|
|
*/
|
2022-08-03 21:21:30 +00:00
|
|
|
virtual bool getWantPreNote();
|
2022-01-20 18:48:20 +00:00
|
|
|
|
2022-12-04 10:58:58 +00:00
|
|
|
/**
|
|
|
|
* get minimum chip clock.
|
|
|
|
* @return clock in Hz, or 0 if custom clocks are not supported.
|
|
|
|
*/
|
2022-12-04 11:02:59 +00:00
|
|
|
virtual int getClockRangeMin();
|
2022-12-04 10:58:58 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* get maximum chip clock.
|
|
|
|
* @return clock in Hz, or 0 if custom clocks are not supported.
|
|
|
|
*/
|
2022-12-04 11:02:59 +00:00
|
|
|
virtual int getClockRangeMax();
|
2022-12-04 10:58:58 +00:00
|
|
|
|
2021-12-18 08:25:42 +00:00
|
|
|
/**
|
2022-01-28 17:59:53 +00:00
|
|
|
* set the chip flags.
|
2022-09-30 01:13:40 +00:00
|
|
|
* @param flags a DivConfig containing chip flags.
|
2021-12-18 08:25:42 +00:00
|
|
|
*/
|
2022-09-30 01:13:40 +00:00
|
|
|
virtual void setFlags(const DivConfig& flags);
|
2021-12-06 21:51:18 +00:00
|
|
|
|
2021-12-21 06:29:07 +00:00
|
|
|
/**
|
|
|
|
* set skip reg writes.
|
|
|
|
*/
|
2022-04-06 23:03:30 +00:00
|
|
|
virtual void setSkipRegisterWrites(bool value);
|
2021-12-21 06:29:07 +00:00
|
|
|
|
2022-01-18 04:59:52 +00:00
|
|
|
/**
|
|
|
|
* notify instrument change.
|
|
|
|
*/
|
|
|
|
virtual void notifyInsChange(int ins);
|
|
|
|
|
2022-01-18 05:25:10 +00:00
|
|
|
/**
|
|
|
|
* notify wavetable change.
|
|
|
|
*/
|
|
|
|
virtual void notifyWaveChange(int wave);
|
|
|
|
|
2022-01-13 22:40:29 +00:00
|
|
|
/**
|
|
|
|
* notify deletion of an instrument.
|
|
|
|
*/
|
|
|
|
virtual void notifyInsDeletion(void* ins);
|
|
|
|
|
2022-03-07 06:48:48 +00:00
|
|
|
/**
|
|
|
|
* notify that playback stopped.
|
|
|
|
*/
|
|
|
|
virtual void notifyPlaybackStop();
|
|
|
|
|
2021-12-21 06:29:07 +00:00
|
|
|
/**
|
|
|
|
* force-retrigger instruments.
|
|
|
|
*/
|
|
|
|
virtual void forceIns();
|
|
|
|
|
2022-01-17 04:21:27 +00:00
|
|
|
/**
|
|
|
|
* enable register dumping.
|
|
|
|
*/
|
2022-01-24 06:01:08 +00:00
|
|
|
virtual void toggleRegisterDump(bool enable);
|
2022-01-17 04:21:27 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* get register writes.
|
|
|
|
*/
|
|
|
|
std::vector<DivRegWrite>& getRegisterWrites();
|
|
|
|
|
2022-02-01 23:08:19 +00:00
|
|
|
/**
|
|
|
|
* poke a register.
|
|
|
|
* @param addr address.
|
|
|
|
* @param val value.
|
|
|
|
*/
|
|
|
|
virtual void poke(unsigned int addr, unsigned short val);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* poke a register.
|
|
|
|
* @param wlist a vector containing DivRegWrites.
|
|
|
|
*/
|
|
|
|
virtual void poke(std::vector<DivRegWrite>& wlist);
|
|
|
|
|
2022-02-03 23:38:57 +00:00
|
|
|
/**
|
|
|
|
* get available registers.
|
|
|
|
* @return an array of C strings, terminated by NULL; or NULL if none available.
|
|
|
|
*/
|
|
|
|
virtual const char** getRegisterSheet();
|
|
|
|
|
2022-05-01 17:57:44 +00:00
|
|
|
/**
|
|
|
|
* Get sample memory buffer.
|
2022-11-26 23:44:04 +00:00
|
|
|
* @param index the memory index.
|
|
|
|
* @return a pointer to sample memory, or NULL.
|
2022-05-01 17:57:44 +00:00
|
|
|
*/
|
|
|
|
virtual const void* getSampleMem(int index = 0);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get sample memory capacity.
|
2022-11-26 23:44:04 +00:00
|
|
|
* @param index the memory index.
|
|
|
|
* @return memory capacity in bytes, or 0 if memory doesn't exist.
|
2022-05-01 17:57:44 +00:00
|
|
|
*/
|
|
|
|
virtual size_t getSampleMemCapacity(int index = 0);
|
|
|
|
|
2022-11-27 03:11:49 +00:00
|
|
|
/**
|
|
|
|
* get sample memory name.
|
|
|
|
* @param index the memory index.
|
|
|
|
* @return a name, or NULL if it doesn't have any name in particular.
|
|
|
|
*/
|
|
|
|
virtual const char* getSampleMemName(int index=0);
|
|
|
|
|
2022-05-01 17:57:44 +00:00
|
|
|
/**
|
|
|
|
* Get sample memory usage.
|
2022-11-26 23:44:04 +00:00
|
|
|
* @param index the memory index.
|
|
|
|
* @return memory usage in bytes.
|
2022-05-01 17:57:44 +00:00
|
|
|
*/
|
|
|
|
virtual size_t getSampleMemUsage(int index = 0);
|
|
|
|
|
2022-11-26 23:44:04 +00:00
|
|
|
/**
|
|
|
|
* check whether sample has been loaded in memory.
|
|
|
|
* @param memory index.
|
|
|
|
* @param sample the sample in question.
|
|
|
|
* @return whether it did.
|
|
|
|
*/
|
|
|
|
virtual bool isSampleLoaded(int index, int sample);
|
|
|
|
|
|
|
|
|
2022-05-01 17:57:44 +00:00
|
|
|
/**
|
|
|
|
* Render samples into sample memory.
|
2022-11-27 04:50:20 +00:00
|
|
|
* @param sysID the chip's index in the chip list.
|
2022-05-01 17:57:44 +00:00
|
|
|
*/
|
2022-11-27 04:50:20 +00:00
|
|
|
virtual void renderSamples(int sysID);
|
2022-05-01 17:57:44 +00:00
|
|
|
|
2021-05-11 20:08:08 +00:00
|
|
|
/**
|
|
|
|
* initialize this DivDispatch.
|
2021-05-12 08:58:55 +00:00
|
|
|
* @param parent the parent DivEngine.
|
2021-05-11 20:08:08 +00:00
|
|
|
* @param channels the number of channels to acquire.
|
2021-05-12 08:58:55 +00:00
|
|
|
* @param sugRate the suggested rate. this may change, so don't rely on it.
|
2022-09-30 01:13:40 +00:00
|
|
|
* @param flags a DivConfig containing chip flags.
|
2021-05-11 20:08:08 +00:00
|
|
|
* @return the number of channels allocated.
|
|
|
|
*/
|
2022-09-30 01:13:40 +00:00
|
|
|
virtual int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
2021-12-15 05:37:27 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* quit the DivDispatch.
|
|
|
|
*/
|
2022-04-27 05:56:15 +00:00
|
|
|
virtual void quit();
|
2021-12-15 05:37:27 +00:00
|
|
|
|
2022-04-27 05:56:15 +00:00
|
|
|
virtual ~DivDispatch();
|
2021-05-11 20:08:08 +00:00
|
|
|
};
|
2022-01-28 05:55:51 +00:00
|
|
|
|
2022-12-04 07:04:42 +00:00
|
|
|
// custom chip clock helper define. put in setFlags, but before rate is set.
|
|
|
|
#define CHECK_CUSTOM_CLOCK \
|
|
|
|
if (flags.getInt("customClock",0)>0) { \
|
2022-12-04 10:58:58 +00:00
|
|
|
chipClock=flags.getInt("customClock",getClockRangeMin()); \
|
|
|
|
if (chipClock>getClockRangeMax()) chipClock=getClockRangeMax(); \
|
|
|
|
if (chipClock<getClockRangeMin()) chipClock=getClockRangeMin(); \
|
2022-12-04 07:04:42 +00:00
|
|
|
}
|
|
|
|
|
2022-04-26 20:24:45 +00:00
|
|
|
// pitch calculation:
|
|
|
|
// - a DivDispatch usually contains four variables per channel:
|
|
|
|
// - baseFreq: this changes on new notes, legato, arpeggio and slides.
|
|
|
|
// - pitch: this changes with DIV_CMD_PITCH (E5xx/04xy).
|
|
|
|
// - freq: this is the result of combining baseFreq and pitch using DivEngine::calcFreq().
|
|
|
|
// - freqChanged: whether baseFreq and/or pitch have changed, and a frequency recalculation is required on the next tick.
|
|
|
|
// - the following definitions will help you calculate baseFreq.
|
|
|
|
// - to use them, define CHIP_DIVIDER and/or CHIP_FREQBASE in your code (not in the header though!).
|
2022-03-24 04:19:16 +00:00
|
|
|
#define NOTE_PERIODIC(x) round(parent->calcBaseFreq(chipClock,CHIP_DIVIDER,x,true))
|
|
|
|
#define NOTE_PERIODIC_NOROUND(x) parent->calcBaseFreq(chipClock,CHIP_DIVIDER,x,true)
|
2022-01-28 05:55:51 +00:00
|
|
|
#define NOTE_FREQUENCY(x) parent->calcBaseFreq(chipClock,CHIP_FREQBASE,x,false)
|
|
|
|
|
2022-04-26 20:24:45 +00:00
|
|
|
// this is a special case definition. only use it for f-num/block-based chips.
|
2022-04-25 03:45:59 +00:00
|
|
|
#define NOTE_FNUM_BLOCK(x,bits) parent->calcBaseFreqFNumBlock(chipClock,CHIP_FREQBASE,x,bits)
|
2022-01-28 05:55:51 +00:00
|
|
|
|
2022-06-01 21:35:39 +00:00
|
|
|
// this is for volume scaling calculation.
|
|
|
|
#define VOL_SCALE_LINEAR(x,y,range) (((x)*(y))/(range))
|
2022-10-28 13:36:50 +00:00
|
|
|
#define VOL_SCALE_LOG(x,y,range) (CLAMP(((x)+(y))-(range),0,(range)))
|
|
|
|
#define VOL_SCALE_LINEAR_BROKEN(x,y,range) ((parent->song.newVolumeScaling)?(VOL_SCALE_LINEAR(x,y,range)):(VOL_SCALE_LOG(x,y,range)))
|
|
|
|
#define VOL_SCALE_LOG_BROKEN(x,y,range) ((parent->song.newVolumeScaling)?(VOL_SCALE_LOG(x,y,range)):(VOL_SCALE_LINEAR(x,y,range)))
|
2022-06-01 21:35:39 +00:00
|
|
|
|
2022-04-26 20:24:45 +00:00
|
|
|
// these are here for convenience.
|
|
|
|
// it is encouraged to use these, since you get an exact value this way.
|
|
|
|
// - NTSC colorburst: 3.58MHz
|
|
|
|
// - PAL colorburst: 4.43MHz
|
2022-01-28 05:55:51 +00:00
|
|
|
#define COLOR_NTSC (315000000.0/88.0)
|
|
|
|
#define COLOR_PAL (283.75*15625.0+25.0)
|
|
|
|
|
2022-04-28 06:31:16 +00:00
|
|
|
#define CLAMP_VAR(x,xMin,xMax) \
|
2022-04-28 14:30:50 +00:00
|
|
|
if ((x)<(xMin)) (x)=(xMin); \
|
|
|
|
if ((x)>(xMax)) (x)=(xMax);
|
2022-04-28 06:31:16 +00:00
|
|
|
|
2022-12-17 06:21:08 +00:00
|
|
|
#define NEW_ARP_STRAT (parent->song.linearPitch==2 && !parent->song.oldArpStrategy)
|
2022-12-17 07:07:24 +00:00
|
|
|
#define HACKY_LEGATO_MESS chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode && !NEW_ARP_STRAT
|
2022-12-17 05:54:56 +00:00
|
|
|
|
2021-05-12 10:22:01 +00:00
|
|
|
#endif
|