dev240 - Merge branch 'inf2' - READ

this introduces several major changes to Furnace. I hope this message explains everything.

**File Format Changes**

a new song info header (`INF2`) has been introduced, which:
- cleans up the mess I made when adding sub-songs to Furnace
- allows better forward compatibility and extensibility
- uses 16-bit chip IDs
- moves compatibility flags to another block and is stored as a DivConfig
- stores channel count in the file, allowing chips with dynamic channel count (e.g. Namco 163)

a new sub-song data block has been introduced as well.

check out papers/format.md for information.

**Furnace Changes**

TimeBase ("Divider" in the UI) has been REMOVED. it was a DefleMask leftover.
to compensate, the speeds are now 16-bit. older songs will have their speeds converted, but this may fail if you use grooves or change speed mid-song.

dynamic channel count support has been added. the following chips are currently supported:
- Namco 163 (1-8 channels)
- ES5506 (5-32 channels)
- Generic PCM DAC (1-128 channels, with software mixing!)

channel colors have been added (thanks Eknous!).

SegaPCM (compatible 5-channel mode) and Neo Geo CD have been REMOVED. when loading previous files, including .dmf ones, these will have compatible SegaPCM and Neo Geo CD chips converted to normal SegaPCM and YM2610 respectively.
their channel count remains unaltered though. you can fix this by going into the chip manager and clicking the button next to "irregular channel count" in each chip config section.

**Code Changes**

a couple refactors have been made for the sake of code cleanliness and depending less on DivEngine...

=> Chip Channel Count

two new values, adjacent to the channel count, have been added to DivSysDef.
these specify the minimum and maximum channel count for a chip.

if your chip doesn't require dynamic channels, feel free to set these to the channel count.

for example, here's an old definition:

```
sysDefs[DIV_SYSTEM_NES]=new DivSysDef(
  _("NES (Ricoh 2A03)"), NULL, 0x06, 0x06, 5 /* channel count*/, false, true, 0x161, false, (1U<<DIV_SAMPLE_DEPTH_1BIT_DPCM)|(1U<<DIV_SAMPLE_DEPTH_8BIT), 0, 0,
  ...
```

and here's how it looks now:

```
sysDefs[DIV_SYSTEM_NES]=new DivSysDef(
  _("NES (Ricoh 2A03)"), NULL, 0x06, 0x06, 5 /* nominal channel count*/, 5 /* min channels */, 5 /* max channels */,
  false, true, 0x161, false, (1U<<DIV_SAMPLE_DEPTH_1BIT_DPCM)|(1U<<DIV_SAMPLE_DEPTH_8BIT), 0, 0,
  ...
```

=> New Channel Definition

a new way to define chip channels has been introduced, replacing the old one.
it looks cleaner and is more flexible (even supporting dynamic channel count).

it works by defining a function in the chip definition, which returns a DivChanDef with channel information (name, short name, type and instrument type(s)).
alternatively, a list can be provided in the DivChanDefFunc() constructor, in the event channels differ greatly and/or the number of channels is small.
for example, if your chip's channel definition code looked like this:

```
{_("Pulse 1"), _("Pulse 2"), _("Triangle"), _("Noise"), _("DPCM")}, // names
{"S1", "S2", "TR", "NO", "DMC"}, // short names
{DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_WAVE, DIV_CH_NOISE, DIV_CH_PCM}, // types
{DIV_INS_NES, DIV_INS_NES, DIV_INS_NES, DIV_INS_NES, DIV_INS_NES}, // ins types
{DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA}, // secondary ins types
```

now they look like this:

```
DivChanDefFunc({
  DivChanDef(_("Pulse 1") , "S1" , DIV_CH_PULSE, DIV_INS_NES),
  DivChanDef(_("Pulse 2") , "S2" , DIV_CH_PULSE, DIV_INS_NES),
  DivChanDef(_("Triangle"), "TR" , DIV_CH_WAVE , DIV_INS_NES),
  DivChanDef(_("Noise")   , "NO" , DIV_CH_NOISE, DIV_INS_NES),
  DivChanDef(_("DPCM")    , "DMC", DIV_CH_PCM  , DIV_INS_NES, DIV_INS_AMIGA)
}),
```

some helper templates, such as stockChanDef and simpleChanDef also exist, which automatically map channel names and types regardless of count.
this is useful if all your channels happen to be named "Channel 1", "Channel 2" and so on, while sharing the same type and instrument type (this is the case for many sampler chips).

if you've been working on a custom chip, make sure to adapt your chip definitions.

=> More Chip Definition Changes

the DivSystem enum is now in src/engine/sysDef.h

channel definitions are cached in the DivSong.

=> Reducing Dependency on DivEngine

many functions have been moved away from DivEngine where possible. these include:

- recalcChans() (now on DivSong)
  - chans, sysOfChan, dispatchOfChan, dispatchChanOfChan and dispatchFirstChan have been moved to DivSong as well.
- asset dir storage/modification/check finctions (now on src/engine/assetDir.cpp)
- DivEngine::getSystemDef() is now a static function, so it can be called without a DivEngine (engine still has to initialize systems first!)

IMPORTANT: hasLoadedSomething is no longer set in recalcChans() because it is part of DivEngine. if you have import code, MAKE SURE TO SET hasLoadedSomething TO true AFTER SWITCHING THE SONG (song=ds).

=> Dynamic Channel Count

a new array called systemChans[] has been added to DivSong, allowing you to define the number of channels for each chip.
if you change this, make sure to call recalcChans() afterwards.

if you use dispatchChanOfChan[], treat `-1` as "no channel". this is set when the channel count is higher than the chip's maximum.

if you're working on import code, and are certain you won't use dynamic channel count, call DivSong::initDefaultSystemChans() before recalcChans(). this will set up default channel counts for you.
otherwise, set systemChans[] appropriately.
This commit is contained in:
tildearrow 2025-11-21 11:26:27 -05:00
commit 6ad8a0893b
131 changed files with 5673 additions and 3997 deletions

View file

@ -782,6 +782,8 @@ src/engine/brrUtils.c
src/engine/safeReader.cpp
src/engine/safeWriter.cpp
src/engine/workPool.cpp
src/engine/assetDir.cpp
src/engine/cmdStream.cpp
src/engine/cmdStreamOps.cpp
src/engine/config.cpp

View file

@ -1,8 +1,6 @@
# the Furnace file format (.fur)
while Furnace works directly with the .dmf format, I had to create a new format to handle future additions to the program.
this document has the goal of detailing the format.
this document has the goal of describing the file format used by Furnace for loading and saving songs.
**notice:** GitHub's Markdown formatter may break on this file as it doesn't seem to treat tables correctly.
@ -120,7 +118,482 @@ size | description
8 | reserved
```
# song info
# song info (>=240)
```
size | description
-----|------------------------------------
4 | "INF2" block ID
4 | size of this block
--- | **song information**
STR | song name
STR | song author
STR | system name
STR | album/category/game name
STR | song name (Japanese)
STR | song author (Japanese)
STR | system name (Japanese)
STR | album/category/game name (Japanese)
4f | A-4 tuning
1 | automatic system name
--- | **system definition**
4f | master volume, 1.0f=100%
2 | total number of channels
2 | number of chips
--- | **chip definition (×numChips)**
2 | chip ID
2 | chip channel count
4f | chip volume
4f | chip panning
4f | chip front/rear balance
--- | **patchbay**
4 | patchbay connection count
4?? | patchbay
| - see next section for more details.
1 | automatic patchbay
--- | **song elements (repeated until element type is 0)**
1 | element type
4 | number of elements
4?? | pointers to elements (×numElements)
```
## list of sound chips
this is a list of sound chips, and their nominal channel count.
the channel count is stored in the file in order to allow Furnace to load files with unsupported chips from derivatives of Furnace or newer versions.
- 0x00: invalid (end of chips in previous versions)
- 0x01: YMU759 - 17 channels
- 0x03: SN76489/Sega PSG - 4 channels
- 0x04: Game Boy - 4 channels
- 0x05: PC Engine - 6 channels
- 0x06: NES - 5 channels
- 0x07: C64 (8580) - 3 channels
- 0x47: C64 (6581) - 3 channels
- 0x80: AY-3-8910 - 3 channels
- 0x81: Amiga - 4 channels
- 0x82: YM2151 - 8 channels
- 0x83: YM2612 - 6 channels
- 0x84: TIA - 2 channels
- 0x85: VIC-20 - 4 channels
- 0x86: PET - 1 channel
- 0x87: SNES - 8 channels
- 0x88: VRC6 - 3 channels
- 0x89: OPLL (YM2413) - 9 channels
- 0x8a: FDS - 1 channel
- 0x8b: MMC5 - 3 channels
- 0x8c: Namco 163 - 8 channels
- 0x8d: YM2203 - 6 channels
- 0x8e: YM2608 - 16 channels
- 0x8f: OPL (YM3526) - 9 channels
- 0x90: OPL2 (YM3812) - 9 channels
- 0x91: OPL3 (YMF262) - 18 channels
- 0x92: MultiPCM - 28 channels
- 0x93: Intel 8253 (beeper) - 1 channel
- 0x94: POKEY - 4 channels
- 0x95: RF5C68 - 8 channels
- 0x96: WonderSwan - 4 channels
- 0x97: Philips SAA1099 - 6 channels
- 0x98: OPZ (YM2414) - 8 channels
- 0x99: Pokémon Mini - 1 channel
- 0x9a: AY8930 - 3 channels
- 0x9b: SegaPCM - 16 channels
- 0x9c: Virtual Boy - 6 channels
- 0x9d: VRC7 - 6 channels
- 0x9e: YM2610B - 16 channels
- 0x9f: ZX Spectrum (beeper, SFX-like tildearrow engine) - 6 channels
- 0xa0: YM2612 extended - 9 channels
- 0xa1: Konami SCC - 5 channels
- 0xa2: OPL drums (YM3526) - 11 channels
- 0xa3: OPL2 drums (YM3812) - 11 channels
- 0xa4: OPL3 drums (YMF262) - 20 channels
- 0xa5: Neo Geo (YM2610) - 14 channels
- 0xa6: Neo Geo extended (YM2610) - 17 channels
- 0xa7: OPLL drums (YM2413) - 11 channels
- 0xa8: Atari Lynx - 4 channels
- 0xaa: MSM6295 - 4 channels
- 0xab: MSM6258 - 1 channel
- 0xac: Commander X16 (VERA) - 17 channels
- 0xad: Bubble System WSG - 2 channels
- 0xae: OPL4 (YMF278B) - 42 channels
- 0xaf: OPL4 drums (YMF278B) - 44 channels
- 0xb0: Seta/Allumer X1-010 - 16 channels
- 0xb1: Ensoniq ES5506 - 32 channels
- 0xb2: Yamaha Y8950 - 10 channels
- 0xb3: Yamaha Y8950 drums - 12 channels
- 0xb4: Konami SCC+ - 5 channels
- 0xb5: tildearrow Sound Unit - 8 channels
- 0xb6: YM2203 extended - 9 channels
- 0xb7: YM2608 extended - 19 channels
- 0xb8: YMZ280B - 8 channels
- 0xb9: Namco WSG - 3 channels
- 0xba: Namco C15 - 8 channels
- 0xbb: Namco C30 - 8 channels
- 0xbc: MSM5232 - 8 channels
- 0xbd: YM2612 DualPCM extended - 11 channels
- 0xbe: YM2612 DualPCM - 7 channels
- 0xbf: T6W28 - 4 channels
- 0xc0: PCM DAC - 1 channel
- 0xc1: YM2612 CSM - 10 channels
- 0xc2: Neo Geo CSM (YM2610) - 18 channels
- 0xc3: YM2203 CSM - 10 channels
- 0xc4: YM2608 CSM - 20 channels
- 0xc5: YM2610B CSM - 20 channels
- 0xc6: K007232 - 2 channels
- 0xc7: GA20 - 4 channels
- 0xc8: SM8521 - 3 channels
- 0xc9: M114S - 16 channels (UNAVAILABLE)
- 0xca: ZX Spectrum (beeper, QuadTone engine) - 5 channels
- 0xcb: Casio PV-1000 - 3 channels
- 0xcc: K053260 - 4 channels
- 0xcd: TED - 2 channels
- 0xce: Namco C140 - 24 channels
- 0xcf: Namco C219 - 16 channels
- 0xd0: Namco C352 - 32 channels (UNAVAILABLE)
- 0xd1: ESFM - 18 channels
- 0xd2: Ensoniq ES5503 (hard pan) - 32 channels (UNAVAILABLE)
- 0xd4: PowerNoise - 4 channels
- 0xd5: Dave - 6 channels
- 0xd6: NDS - 16 channels
- 0xd7: Game Boy Advance (direct) - 2 channels
- 0xd8: Game Boy Advance (MinMod) - 16 channels
- 0xd9: Bifurcator - 4 channels
- 0xda: SCSP - 32 channels (UNAVAILABLE)
- 0xdb: YMF271 (OPX) - 48 channels (UNAVAILABLE)
- 0xdc: RF5C400 - 32 channels (UNAVAILABLE)
- 0xdd: YM2612 XGM - 9 channels (UNAVAILABLE)
- 0xde: YM2610B extended - 19 channels
- 0xdf: YM2612 XGM extended - 13 channels (UNAVAILABLE)
- 0xe0: QSound - 19 channels
- 0xe1: PS1 - 24 channels (UNAVAILABLE)
- 0xe2: C64 (6581) with PCM - 4 channels
- 0xe3: Watara Supervision - 4 channels
- 0xe5: µPD1771C-017 - 4 channels
- 0xf0: SID2 - 3 channels
- 0xf1: 5E01 - 5 channels
- 0xf5: SID3 - 7 channels
- 0xfc: Pong - 1 channel
- 0xfd: Dummy System - 8 channels
- 0xfe: reserved for development
- 0xff: reserved for development
notes:
- (UNAVAILABLE) means that the chip hasn't been implemented in Furnace yet.
### special IDs
the following is a list of legacy chip/system IDs.
these must be either flattened (converted to two equivalent chips) or converted to another chip.
those marked with `(compound!)` were from an era where two chips were part of a single system ID.
these IDs will never be present in new song files (with the `INF2` info header). if you see them, reject the file.
- 0x02: Genesis - 10 channels (compound!)
- flatten to 0x83 (YM2612) + 0x03 (SN76489/Sega PSG)
- 0x08: Arcade (YM2151+SegaPCM) - 13 channels (compound!)
- flatten to 0x82 (YM2151) + 0x9b (SegaPCM)
- channel count of the latter shall be 5!
- 0x09: Neo Geo CD (YM2610) - 13 channels
- convert to 0xa5 (YM2610 proper) and set channel count to 13
- 0x42: Genesis extended - 13 channels (compound!)
- flatten to 0xa0 (YM2612 extended) + 0x03 (SN76489/Sega PSG)
- 0x43: SMS (SN76489) + OPLL (YM2413) - 13 channels (compound!)
- flatten to 0x03 (SN76489/Sega PSG) + 0x89 (OPLL)
- 0x46: NES + VRC7 - 11 channels (compound!)
- flatten to 0x06 (NES) + 0x9d (VRC7)
- 0x49: Neo Geo CD extended - 16 channels
- convert to 0xa6 (YM2610 extended proper) and set channel count to 16
- 0xa9: SegaPCM (for DefleMask compatibility) - 5 channels
- convert to 0x9b (SegaPCM) and set channel count to 5
## song elements
the following element types are available:
```
## | ID | description
----|------|-----------------------------
00 | ---- | end of element list (end of info header)
01 | SNG2 | sub-song
02 | FLAG | chip flags
03 | ADIR | asset directory**
04 | INS2 | instrument
05 | WAVE | wavetable
06 | SMP2 | sample
07 | PATN | pattern
08 | CFLG | compatibility flags*
09 | CMNT | song comments*
0a | GROV | groove pattern
* element is unique (number of elements shall be 1)
** first pointer is for instruments, second for wavetables and third for samples
```
# patchbay
Furnace dev135 adds a "patchbay" which allows for arbitrary connection of chip outputs to system outputs.
it also allows connecting outputs to effects and so on.
a connection is represented as an unsigned int in the following format:
- bit 16-31: source port
- bit 0-15: destination port
a port is in the following format (hexadecimal): `xxxy`
- `xxx` (bit 4 to 15) represents a portset.
- `y` (bit 0 to 3) is the port in that portset.
reserved input portsets:
- `000`: system outputs
- `FFF`: "null" portset
reserved output portsets:
- `000` through `chipCount`: chip outputs
- `FFC`: reference file/music player (>=238)
- `FFD`: wave/sample preview
- `FFE`: metronome
- `FFF`: "null" portset
# subsong (>=240)
```
size | description
-----|------------------------------------
4 | "SNG2" block ID
4 | size of this block
4f | ticks per second
| - 60 is NTSC
| - 50 is PAL
1 | initial arpeggio speed
1 | effect speed divider
2 | pattern length
| - the limit is 256.
2 | orders length
| - the limit is 256.
1 | highlight A (rows per beat)
1 | highlight B (rows per bar)
2 | virtual tempo numerator
2 | virtual tempo denominator
1 | length of speed pattern in entries (fail if this is lower than 1 or higher than 16)
2?? | speed pattern (always 16 entries)
| - each speed is an unsigned short
STR | subsong name
STR | subsong comment
??? | orders
| - a table of bytes
| - size=channels*ordLen
| - read orders then channels
| - the maximum value of a cell is FF.
??? | effect columns
| - size=channels
1?? | channel hide status
| - size=channels
1?? | channel collapse status
| - size=channels
S?? | channel names
| - a list of channelCount C strings
S?? | channel short names
| - same as above
4?? | channel colors
| - read 4 values per color (ABGR)
| - if 0, use default color
```
# groove pattern (>=240)
```
size | description
-----|------------------------------------
4 | "GROV" block ID
4 | size of this block
1 | length of groove in entries (fail if this is lower than 1 or higher than 16)
2?? | groove pattern (always 16 entries)
| - each speed is an unsigned short
```
# chip flags
```
size | description
-----|------------------------------------
4 | "FLAG" block ID
4 | size of this block
STR | data
```
flags are stored in text (`key=value`) format. for example:
```
clock=4000000
stereo=true
```
# asset directories (>=156)
also known as "folder" in the user interface.
```
size | description
-----|------------------------------------
4 | "ADIR" block ID
4 | size of this block
4 | number of directories
--- | **asset directory** (×numberOfDirs)
STR | name (if empty, this is the uncategorized directory)
2 | number of assets
1?? | assets in this directory
```
# instrument (>=127)
Furnace dev127 and higher use the new instrument format.
```
size | description
-----|------------------------------------
4 | "INS2" block ID
4 | size of this block
2 | format version
2 | instrument type
??? | features...
```
see [newIns.md](newIns.md) for more information.
# wavetable
```
size | description
-----|------------------------------------
4 | "WAVE" block ID
4 | size of this block
STR | wavetable name
4 | wavetable width
4 | reserved
4 | wavetable height
4?? | wavetable data
```
# sample (>=102)
```
size | description
-----|------------------------------------
4 | "SMP2" block ID
4 | size of this block
STR | sample name
4 | length
4 | compatibility rate
4 | C-4 rate
1 | depth
| - 0: ZX Spectrum overlay drum (1-bit)
| - 1: 1-bit NES DPCM (1-bit)
| - 3: YMZ ADPCM
| - 4: QSound ADPCM
| - 5: ADPCM-A
| - 6: ADPCM-B
| - 7: K05 ADPCM
| - 8: 8-bit PCM
| - 9: BRR (SNES)
| - 10: VOX
| - 11: 8-bit μ-law PCM
| - 12: C219 PCM
| - 13: IMA ADPCM
| - 14: 12-bit PCM (MultiPCM)
| - 16: 16-bit PCM
1 | loop direction (>=123) or reserved
| - 0: forward
| - 1: backward
| - 2: ping-pong
1 | flags (>=129) or reserved
| - 0: BRR emphasis
1 | flags 2 (>=159) or reserved
| - 0: dither
| - 1: no BRR filters (>=213)
4 | loop start
| - -1 means no loop
4 | loop end
| - -1 means no loop
16 | sample presence bitfields
| - for future use.
| - indicates whether the sample should be present in the memory of a system.
| - read 4 32-bit numbers (for 4 memory banks per system, e.g. YM2610
| does ADPCM-A and ADPCM-B on separate memory banks).
??? | sample data
| - size is length
```
# pattern (>=157)
```
size | description
-----|------------------------------------
4 | "PATN" block ID
4 | size of this block
1 | subsong
1 | channel (<240)
2 | channel (>=240)
| - the channel index was 8-bit in previous versions.
| - in order to accommodate higher channel counts, it has been extended to 16-bit.
2 | pattern index
STR | pattern name (>=51)
??? | pattern data
| - read a byte per row.
| - if it is 0xff, end of data. the rest of the pattern is empty.
| - if bit 7 is set, then skip N+2 rows. N is bits 0-6.
| - for example, $80 means skip 2 rows, $81 means skip 3, $82 means 4 and so on.
| - if bit 7 is clear, then:
| - bit 0: note present
| - bit 1: ins present
| - bit 2: volume present
| - bit 3: effect 0 present
| - bit 4: effect value 0 present
| - bit 5: other effects (0-3) present
| - bit 6: other effects (4-7) present
| - if none of these bits are set, then skip 1 row.
| - if bit 5 is set, read another byte:
| - bit 0: effect 0 present
| - bit 1: effect value 0 present
| - bit 2: effect 1 present
| - bit 3: effect value 1 present
| - bit 4: effect 2 present
| - bit 5: effect value 2 present
| - bit 6: effect 3 present
| - bit 7: effect value 3 present
| - if bit 6 is set, read another byte:
| - bit 0: effect 4 present
| - bit 1: effect value 4 present
| - bit 2: effect 5 present
| - bit 3: effect value 5 present
| - bit 4: effect 6 present
| - bit 5: effect value 6 present
| - bit 6: effect 7 present
| - bit 7: effect value 7 present
| - then read note, ins, volume, effects and effect values depending on what is present.
| - for note:
| - 0 is C-(-5)
| - 179 is B-9
| - 180 is note off
| - 181 is note release
| - 182 is macro release
```
---
# old format blocks
these were present in previous versions of the Furnace file format.
## old song info (<240)
hic sunt dracones!
this info block is messy because it was devised during Furnace's early days, back when it didn't support sub-songs.
the first sub-song is defined here. compatibility flags are all over the place.
```
size | description
@ -147,134 +620,9 @@ size | description
2 | sample count
| - the limit is 256.
4 | pattern count (global)
32 | list of sound chips
| - possible soundchips:
| - 0x00: end of list
| - 0x01: YMU759 - 17 channels
| - 0x02: Genesis - 10 channels (compound!)
| - 0x03: SMS (SN76489) - 4 channels
| - 0x04: Game Boy - 4 channels
| - 0x05: PC Engine - 6 channels
| - 0x06: NES - 5 channels
| - 0x07: C64 (8580) - 3 channels
| - 0x08: Arcade (YM2151+SegaPCM) - 13 channels (compound!)
| - 0x09: Neo Geo CD (YM2610) - 13 channels
| - 0x42: Genesis extended - 13 channels
| - 0x43: SMS (SN76489) + OPLL (YM2413) - 13 channels (compound!)
| - 0x46: NES + VRC7 - 11 channels (compound!)
| - 0x47: C64 (6581) - 3 channels
| - 0x49: Neo Geo CD extended - 16 channels
| - 0x80: AY-3-8910 - 3 channels
| - 0x81: Amiga - 4 channels
| - 0x82: YM2151 - 8 channels
| - 0x83: YM2612 - 6 channels
| - 0x84: TIA - 2 channels
| - 0x85: VIC-20 - 4 channels
| - 0x86: PET - 1 channel
| - 0x87: SNES - 8 channels
| - 0x88: VRC6 - 3 channels
| - 0x89: OPLL (YM2413) - 9 channels
| - 0x8a: FDS - 1 channel
| - 0x8b: MMC5 - 3 channels
| - 0x8c: Namco 163 - 8 channels
| - 0x8d: YM2203 - 6 channels
| - 0x8e: YM2608 - 16 channels
| - 0x8f: OPL (YM3526) - 9 channels
| - 0x90: OPL2 (YM3812) - 9 channels
| - 0x91: OPL3 (YMF262) - 18 channels
| - 0x92: MultiPCM - 28 channels
| - 0x93: Intel 8253 (beeper) - 1 channel
| - 0x94: POKEY - 4 channels
| - 0x95: RF5C68 - 8 channels
| - 0x96: WonderSwan - 4 channels
| - 0x97: Philips SAA1099 - 6 channels
| - 0x98: OPZ (YM2414) - 8 channels
| - 0x99: Pokémon Mini - 1 channel
| - 0x9a: AY8930 - 3 channels
| - 0x9b: SegaPCM - 16 channels
| - 0x9c: Virtual Boy - 6 channels
| - 0x9d: VRC7 - 6 channels
| - 0x9e: YM2610B - 16 channels
| - 0x9f: ZX Spectrum (beeper, SFX-like tildearrow engine) - 6 channels
| - 0xa0: YM2612 extended - 9 channels
| - 0xa1: Konami SCC - 5 channels
| - 0xa2: OPL drums (YM3526) - 11 channels
| - 0xa3: OPL2 drums (YM3812) - 11 channels
| - 0xa4: OPL3 drums (YMF262) - 20 channels
| - 0xa5: Neo Geo (YM2610) - 14 channels
| - 0xa6: Neo Geo extended (YM2610) - 17 channels
| - 0xa7: OPLL drums (YM2413) - 11 channels
| - 0xa8: Atari Lynx - 4 channels
| - 0xa9: SegaPCM (for DefleMask compatibility) - 5 channels
| - 0xaa: MSM6295 - 4 channels
| - 0xab: MSM6258 - 1 channel
| - 0xac: Commander X16 (VERA) - 17 channels
| - 0xad: Bubble System WSG - 2 channels
| - 0xae: OPL4 (YMF278B) - 42 channels
| - 0xaf: OPL4 drums (YMF278B) - 44 channels
| - 0xb0: Seta/Allumer X1-010 - 16 channels
| - 0xb1: Ensoniq ES5506 - 32 channels
| - 0xb2: Yamaha Y8950 - 10 channels
| - 0xb3: Yamaha Y8950 drums - 12 channels
| - 0xb4: Konami SCC+ - 5 channels
| - 0xb5: tildearrow Sound Unit - 8 channels
| - 0xb6: YM2203 extended - 9 channels
| - 0xb7: YM2608 extended - 19 channels
| - 0xb8: YMZ280B - 8 channels
| - 0xb9: Namco WSG - 3 channels
| - 0xba: Namco C15 - 8 channels
| - 0xbb: Namco C30 - 8 channels
| - 0xbc: MSM5232 - 8 channels
| - 0xbd: YM2612 DualPCM extended - 11 channels
| - 0xbe: YM2612 DualPCM - 7 channels
| - 0xbf: T6W28 - 4 channels
| - 0xc0: PCM DAC - 1 channel
| - 0xc1: YM2612 CSM - 10 channels
| - 0xc2: Neo Geo CSM (YM2610) - 18 channels
| - 0xc3: YM2203 CSM - 10 channels
| - 0xc4: YM2608 CSM - 20 channels
| - 0xc5: YM2610B CSM - 20 channels
| - 0xc6: K007232 - 2 channels
| - 0xc7: GA20 - 4 channels
| - 0xc8: SM8521 - 3 channels
| - 0xc9: M114S - 16 channels (UNAVAILABLE)
| - 0xca: ZX Spectrum (beeper, QuadTone engine) - 5 channels
| - 0xcb: Casio PV-1000 - 3 channels
| - 0xcc: K053260 - 4 channels
| - 0xcd: TED - 2 channels
| - 0xce: Namco C140 - 24 channels
| - 0xcf: Namco C219 - 16 channels
| - 0xd0: Namco C352 - 32 channels (UNAVAILABLE)
| - 0xd1: ESFM - 18 channels
| - 0xd2: Ensoniq ES5503 (hard pan) - 32 channels (UNAVAILABLE)
| - 0xd4: PowerNoise - 4 channels
| - 0xd5: Dave - 6 channels
| - 0xd6: NDS - 16 channels
| - 0xd7: Game Boy Advance (direct) - 2 channels
| - 0xd8: Game Boy Advance (MinMod) - 16 channels
| - 0xd9: Bifurcator - 4 channels
| - 0xda: SCSP - 32 channels (UNAVAILABLE)
| - 0xdb: YMF271 (OPX) - 48 channels (UNAVAILABLE)
| - 0xdc: RF5C400 - 32 channels (UNAVAILABLE)
| - 0xdd: YM2612 XGM - 9 channels (UNAVAILABLE)
| - 0xde: YM2610B extended - 19 channels
| - 0xdf: YM2612 XGM extended - 13 channels (UNAVAILABLE)
| - 0xe0: QSound - 19 channels
| - 0xe1: PS1 - 24 channels (UNAVAILABLE)
| - 0xe2: C64 (6581) with PCM - 4 channels
| - 0xe3: Watara Supervision - 4 channels
| - 0xe5: µPD1771C-017 - 4 channels
| - 0xf0: SID2 - 3 channels
| - 0xf1: 5E01 - 5 channels
| - 0xf5: SID3 - 7 channels
| - 0xfc: Pong - 1 channel
| - 0xfd: Dummy System - 8 channels
| - 0xfe: reserved for development
| - 0xff: reserved for development
| - (compound!) means that the system is composed of two or more chips,
| and has to be flattened.
| - (UNAVAILABLE) means that the chip hasn't been implemented in Furnace
| yet.
32 | list of sound chip IDs
| - 0x00 means "end of chip list". you must read 32 bytes regardless.
| - see list at the top of this file for the list of sound chips.
32 | sound chip volumes (<135) or reserved
| - signed char, 64=1.0, 127=~2.0
| - as of version 135 these fields only exist for compatibility reasons.
@ -411,36 +759,7 @@ size | description
4 | sample directories
```
# patchbay
Furnace dev135 adds a "patchbay" which allows for arbitrary connection of chip outputs to system outputs.
it also allows connecting outputs to effects and so on.
a connection is represented as an unsigned int in the following format:
- bit 16-31: source port
- bit 0-15: destination port
a port is in the following format (hexadecimal): `xxxy`
- `xxx` (bit 4 to 15) represents a portset.
- `y` (bit 0 to 3) is the port in that portset.
reserved input portsets:
- `000`: system outputs
- `FFF`: "null" portset
reserved output portsets:
- `000` through `01F`: chip outputs
- `FFC`: reference file/music player (>=238)
- `FFD`: wave/sample preview
- `FFE`: metronome
- `FFF`: "null" portset
# subsong
from version 95 onwards, Furnace supports storing multiple songs on a single file.
the way it's currently done is really weird, but it provides for some backwards compatibility (previous versions will only load the first subsong which is already defined in the `INFO` block).
# old subsong (<240)
```
size | description
@ -484,60 +803,12 @@ size | description
16 | speed pattern (this overrides speed 1 and speed 2 settings)
```
# chip flags
```
size | description
-----|------------------------------------
4 | "FLAG" block ID
4 | size of this block
STR | data
```
flags are stored in text (`key=value`) format. for example:
```
clock=4000000
stereo=true
```
# asset directories (>=156)
also known as "folder" in the user interface.
```
size | description
-----|------------------------------------
4 | "ADIR" block ID
4 | size of this block
4 | number of directories
--- | **asset directory** (×numberOfDirs)
STR | name (if empty, this is the uncategorized directory)
2 | number of assets
1?? | assets in this directory
```
# instrument (>=127)
Furnace dev127 and higher use the new instrument format.
```
size | description
-----|------------------------------------
4 | "INS2" block ID
4 | size of this block
2 | format version
2 | instrument type
??? | features...
```
see [newIns.md](newIns.md) for more information.
# old instrument (<127)
## old instrument (<127)
instruments in older versions of Furnace used a different format. see [oldIns.md](oldIns.md) for more information.
## C64 compatibility note (>=187)
### C64 compatibility note (>=187)
in Furnace dev187 the volume and cutoff macros have been separated, as noted above.
however, there are two other changes as well: **inverted relative (non-absolute) cutoff macro**; and a new, improved Special macro.
@ -555,74 +826,7 @@ if version is less than 187, you must convert the Special macro:
don't worry about loop or release...
# wavetable
```
size | description
-----|------------------------------------
4 | "WAVE" block ID
4 | size of this block
STR | wavetable name
4 | wavetable width
4 | reserved
4 | wavetable height
4?? | wavetable data
```
# sample (>=102)
this is the new sample storage format used in Furnace dev102 and higher.
```
size | description
-----|------------------------------------
4 | "SMP2" block ID
4 | size of this block
STR | sample name
4 | length
4 | compatibility rate
4 | C-4 rate
1 | depth
| - 0: ZX Spectrum overlay drum (1-bit)
| - 1: 1-bit NES DPCM (1-bit)
| - 3: YMZ ADPCM
| - 4: QSound ADPCM
| - 5: ADPCM-A
| - 6: ADPCM-B
| - 7: K05 ADPCM
| - 8: 8-bit PCM
| - 9: BRR (SNES)
| - 10: VOX
| - 11: 8-bit μ-law PCM
| - 12: C219 PCM
| - 13: IMA ADPCM
| - 14: 12-bit PCM (MultiPCM)
| - 16: 16-bit PCM
1 | loop direction (>=123) or reserved
| - 0: forward
| - 1: backward
| - 2: ping-pong
1 | flags (>=129) or reserved
| - 0: BRR emphasis
1 | flags 2 (>=159) or reserved
| - 0: dither
| - 1: no BRR filters (>=213)
4 | loop start
| - -1 means no loop
4 | loop end
| - -1 means no loop
16 | sample presence bitfields
| - for future use.
| - indicates whether the sample should be present in the memory of a system.
| - read 4 32-bit numbers (for 4 memory banks per system, e.g. YM2610
| does ADPCM-A and ADPCM-B on separate memory banks).
??? | sample data
| - size is length
```
# old sample (<102)
this format is present when saving using previous Furnace versions.
## old sample (<102)
```
size | description
@ -654,60 +858,7 @@ size | description
| - version>=58 size is length
```
# pattern (>=157)
```
size | description
-----|------------------------------------
4 | "PATN" block ID
4 | size of this block
1 | subsong
1 | channel
2 | pattern index
STR | pattern name (>=51)
??? | pattern data
| - read a byte per row.
| - if it is 0xff, end of data. the rest of the pattern is empty.
| - if bit 7 is set, then skip N+2 rows. N is bits 0-6.
| - for example, $80 means skip 2 rows, $81 means skip 3, $82 means 4 and so on.
| - if bit 7 is clear, then:
| - bit 0: note present
| - bit 1: ins present
| - bit 2: volume present
| - bit 3: effect 0 present
| - bit 4: effect value 0 present
| - bit 5: other effects (0-3) present
| - bit 6: other effects (4-7) present
| - if none of these bits are set, then skip 1 row.
| - if bit 5 is set, read another byte:
| - bit 0: effect 0 present
| - bit 1: effect value 0 present
| - bit 2: effect 1 present
| - bit 3: effect value 1 present
| - bit 4: effect 2 present
| - bit 5: effect value 2 present
| - bit 6: effect 3 present
| - bit 7: effect value 3 present
| - if bit 6 is set, read another byte:
| - bit 0: effect 4 present
| - bit 1: effect value 4 present
| - bit 2: effect 5 present
| - bit 3: effect value 5 present
| - bit 4: effect 6 present
| - bit 5: effect value 6 present
| - bit 6: effect 7 present
| - bit 7: effect value 7 present
| - then read note, ins, volume, effects and effect values depending on what is present.
| - for note:
| - 0 is C-(-5)
| - 179 is B-9
| - 180 is note off
| - 181 is note release
| - 182 is macro release
```
# old pattern (<157)
## old pattern (<157)
```
size | description
@ -750,17 +901,3 @@ size | description
| - for instrument, volume, effect and effect data, a value of -1 means empty.
STR | pattern name (>=51)
```
# the Furnace wavetable format (.fuw)
similar to the instrument format...
```
size | description
-----|------------------------------------
16 | "-Furnace waveta-" format magic
2 | format version
2 | reserved
```
wavetable data follows.

13
papers/wavetable.md Normal file
View file

@ -0,0 +1,13 @@
# the Furnace wavetable format (.fuw)
similar to the instrument format...
```
size | description
-----|------------------------------------
16 | "-Furnace waveta-" format magic
2 | format version
2 | reserved
```
wavetable data follows.

152
src/engine/assetDir.cpp Normal file
View file

@ -0,0 +1,152 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2025 tildearrow and contributors
*
* 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.
*/
#include "assetDir.h"
#include "../ta-log.h"
void moveAsset(std::vector<DivAssetDir>& dir, int before, int after) {
if (before<0 || after<0) return;
for (DivAssetDir& i: dir) {
for (size_t j=0; j<i.entries.size(); j++) {
// erase matching entry
if (i.entries[j]==before) {
i.entries[j]=after;
} else if (i.entries[j]==after) {
i.entries[j]=before;
}
}
}
}
void removeAsset(std::vector<DivAssetDir>& dir, int entry) {
if (entry<0) return;
for (DivAssetDir& i: dir) {
for (size_t j=0; j<i.entries.size(); j++) {
// erase matching entry
if (i.entries[j]==entry) {
i.entries.erase(i.entries.begin()+j);
j--;
} else if (i.entries[j]>entry) {
i.entries[j]--;
}
}
}
}
void checkAssetDir(std::vector<DivAssetDir>& dir, size_t entries) {
bool* inAssetDir=new bool[entries];
memset(inAssetDir,0,entries*sizeof(bool));
for (DivAssetDir& i: dir) {
for (size_t j=0; j<i.entries.size(); j++) {
// erase invalid entry
if (i.entries[j]<0 || i.entries[j]>=(int)entries) {
i.entries.erase(i.entries.begin()+j);
j--;
continue;
}
// erase duplicate entry
if (inAssetDir[i.entries[j]]) {
i.entries.erase(i.entries.begin()+j);
j--;
continue;
}
// mark entry as present
inAssetDir[i.entries[j]]=true;
}
}
// get unsorted directory
DivAssetDir* unsortedDir=NULL;
for (DivAssetDir& i: dir) {
if (i.name.empty()) {
unsortedDir=&i;
break;
}
}
// add missing items to unsorted directory
for (size_t i=0; i<entries; i++) {
if (!inAssetDir[i]) {
// create unsorted directory if it doesn't exist
if (unsortedDir==NULL) {
dir.push_back(DivAssetDir(""));
unsortedDir=&(*dir.rbegin());
}
unsortedDir->entries.push_back(i);
}
}
delete[] inAssetDir;
}
void putAssetDirData(SafeWriter* w, std::vector<DivAssetDir>& dir) {
size_t blockStartSeek, blockEndSeek;
w->write("ADIR",4);
blockStartSeek=w->tell();
w->writeI(0);
w->writeI(dir.size());
for (DivAssetDir& i: dir) {
w->writeString(i.name,false);
w->writeS(i.entries.size());
for (int j: i.entries) {
w->writeC(j);
}
}
blockEndSeek=w->tell();
w->seek(blockStartSeek,SEEK_SET);
w->writeI(blockEndSeek-blockStartSeek-4);
w->seek(0,SEEK_END);
}
DivDataErrors readAssetDirData(SafeReader& reader, std::vector<DivAssetDir>& dir) {
char magic[4];
reader.read(magic,4);
if (memcmp(magic,"ADIR",4)!=0) {
logV("header is invalid: %c%c%c%c",magic[0],magic[1],magic[2],magic[3]);
return DIV_DATA_INVALID_HEADER;
}
reader.readI(); // reserved
unsigned int numDirs=reader.readI();
dir.reserve(numDirs);
for (unsigned int i=0; i<numDirs; i++) {
DivAssetDir d;
d.name=reader.readString();
unsigned short numEntries=reader.readS();
d.entries.reserve(numEntries);
for (unsigned short j=0; j<numEntries; j++) {
d.entries.push_back(((unsigned char)reader.readC()));
}
dir.push_back(d);
}
return DIV_DATA_SUCCESS;
}

52
src/engine/assetDir.h Normal file
View file

@ -0,0 +1,52 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2025 tildearrow and contributors
*
* 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.
*/
#ifndef _ASSET_DIR_H
#define _ASSET_DIR_H
#include "../ta-utils.h"
#include <vector>
#include "dataErrors.h"
#include "safeReader.h"
#include "safeWriter.h"
struct DivAssetDir {
String name;
std::vector<int> entries;
DivAssetDir():
name("New Directory") {}
DivAssetDir(String n):
name(n) {}
};
// check whether an asset directory is complete (UNSAFE)
void checkAssetDir(std::vector<DivAssetDir>& dir, size_t entries);
// move an asset
void moveAsset(std::vector<DivAssetDir>& dir, int before, int after);
// remove an asset
void removeAsset(std::vector<DivAssetDir>& dir, int entry);
// read/write asset dir
void putAssetDirData(SafeWriter* w, std::vector<DivAssetDir>& dir);
DivDataErrors readAssetDirData(SafeReader& reader, std::vector<DivAssetDir>& dir);
#endif

View file

@ -596,7 +596,7 @@ bool DivCSPlayer::tick() {
}
if (chan[i].portaSpeed) {
e->dispatchCmd(DivCommand(DIV_CMD_NOTE_PORTA,i,chan[i].portaSpeed*(e->song.linearPitch?e->song.pitchSlideSpeed:1),chan[i].portaTarget));
e->dispatchCmd(DivCommand(DIV_CMD_NOTE_PORTA,i,chan[i].portaSpeed*(e->song.compatFlags.linearPitch?e->song.compatFlags.pitchSlideSpeed:1),chan[i].portaTarget));
}
if (chan[i].arp && !chan[i].portaSpeed) {
if (chan[i].arpTicks==0) {
@ -704,7 +704,12 @@ bool DivCSPlayer::init() {
// initialize state
for (int i=0; i<e->getTotalChannelCount(); i++) {
chan[i].volMax=(e->getDispatch(e->dispatchOfChan[i])->dispatch(DivCommand(DIV_CMD_GET_VOLMAX,e->dispatchChanOfChan[i]))<<8)|0xff;
if (e->song.dispatchChanOfChan[i]>=0) {
chan[i].volMax=(e->getDispatch(e->song.dispatchOfChan[i])->dispatch(DivCommand(DIV_CMD_GET_VOLMAX,e->song.dispatchChanOfChan[i]))<<8)|0xff;
} else {
// fallback
chan[i].volMax=0xfff;
}
chan[i].volume=chan[i].volMax;
}

View file

@ -1303,7 +1303,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
// write header
w->write("FCS",4);
w->writeS(chans);
w->writeS(song.chans);
// flags
w->writeC((options.longPointers?1:0)|(options.bigEndian?2:0));
// reserved
@ -1313,7 +1313,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
w->writeC(0);
}
// offsets
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
chanStream[i]=new SafeWriter;
chanStream[i]->init();
if (options.longPointers) {
@ -1323,7 +1323,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
}
}
// max stack sizes
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
w->writeC(0);
}
@ -1338,7 +1338,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
// PASS 0: play the song and log channel command streams
// song beginning marker
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
chanStream[i]->writeC(0xd0);
chanStream[i]->writeC(i);
chanStream[i]->writeC(0x00);
@ -1350,7 +1350,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
chanStream[i]->writeC(0x00);
}
while (!done) {
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
tickPos[i].push_back(chanStream[i]->tell());
}
if (loopTick==-1) {
@ -1359,7 +1359,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
logI("loop is on tick %d",tick);
loopTick=tick;
// loop marker
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
chanStream[i]->writeC(0xd0);
chanStream[i]->writeC(i);
chanStream[i]->writeC(0x00);
@ -1410,7 +1410,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
}
}
cmdStream.clear();
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
chanStream[i]->writeC(0xde);
// padding
chanStream[i]->writeC(0x00);
@ -1424,7 +1424,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
tick++;
}
if (!playing || loopTick<0) {
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
chanStream[i]->writeC(0xdf);
// padding
chanStream[i]->writeC(0x00);
@ -1436,7 +1436,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
chanStream[i]->writeC(0x00);
}
} else {
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
if ((int)tickPos[i].size()>loopTick) {
chanStream[i]->writeC(0xda);
chanStream[i]->writeI(tickPos[i][loopTick]);
@ -1494,7 +1494,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
}
// set preset instruments
for (int h=0; h<chans; h++) {
for (int h=0; h<song.chans; h++) {
unsigned char* buf=chanStream[h]->getFinalBuf();
for (size_t i=0; i<chanStream[h]->size(); i+=8) {
if (buf[i]==0xb8) {
@ -1536,7 +1536,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
}
// set preset volumes
for (int h=0; h<chans; h++) {
for (int h=0; h<song.chans; h++) {
unsigned char* buf=chanStream[h]->getFinalBuf();
for (size_t i=0; i<chanStream[h]->size(); i+=8) {
if (buf[i]==0xc7) {
@ -1578,7 +1578,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
}
// set speed dial commands
for (int h=0; h<chans; h++) {
for (int h=0; h<song.chans; h++) {
unsigned char* buf=chanStream[h]->getFinalBuf();
for (size_t i=0; i<chanStream[h]->size(); i+=8) {
if (buf[i]==0xd7) {
@ -1601,7 +1601,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
// PASS 2: condense delays
if (!options.noDelayCondense) {
// calculate delay usage
for (int h=0; h<chans; h++) {
for (int h=0; h<song.chans; h++) {
unsigned char* buf=chanStream[h]->getFinalBuf();
int delayCount=0;
for (size_t i=0; i<chanStream[h]->size(); i+=8) {
@ -1639,7 +1639,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
}
// condense delays
for (int h=0; h<chans; h++) {
for (int h=0; h<song.chans; h++) {
unsigned char* buf=chanStream[h]->getFinalBuf();
int delayPos=-1;
int delayCount=0;
@ -1693,7 +1693,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
// PASS 3: note off + one-tick wait
// optimize one-tick gaps sometimes used in songs
for (int h=0; h<chans; h++) {
for (int h=0; h<song.chans; h++) {
unsigned char* buf=chanStream[h]->getFinalBuf();
if (chanStream[h]->size()<8) continue;
for (size_t i=0; i<chanStream[h]->size()-8; i+=8) {
@ -1714,12 +1714,12 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
// PASS 4: remove nop's
// this includes modifying call addresses to compensate
for (int h=0; h<chans; h++) {
for (int h=0; h<song.chans; h++) {
chanStream[h]=stripNops(chanStream[h]);
}
// PASS 5: put all channels together
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
chanStreamOff[i]=globalStream->tell();
logI("- %d: off %x size %ld",i,chanStreamOff[i],chanStream[i]->size());
reloc8(chanStream[i]->getFinalBuf(),chanStream[i]->size(),0,globalStream->tell());
@ -1798,7 +1798,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
// also find new offsets
globalStream=stripNopsPacked(globalStream,sortedCmd,chanStreamOff);
for (int h=0; h<chans; h++) {
for (int h=0; h<song.chans; h++) {
chanStreamOff[h]+=w->tell();
}
@ -1807,7 +1807,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
w->write(globalStream->getFinalBuf(),globalStream->size());
// calculate max stack sizes
for (int h=0; h<chans; h++) {
for (int h=0; h<song.chans; h++) {
std::stack<unsigned int> callStack;
unsigned int maxStackSize=0;
unsigned char* buf=w->getFinalBuf();
@ -1866,7 +1866,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
delete globalStream;
w->seek(40,SEEK_SET);
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
if (options.longPointers) {
if (options.bigEndian) {
w->writeI_BE(chanStreamOff[i]);
@ -1884,7 +1884,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
logD("maximum stack sizes:");
unsigned int cumulativeStackSize=0;
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
w->writeC(chanStackSize[i]);
logD("- %d: %d",i,chanStackSize[i]);
cumulativeStackSize+=chanStackSize[i];

View file

@ -1082,10 +1082,10 @@ class DivDispatch {
#define NOTE_FNUM_BLOCK(x,bits,blk) parent->calcBaseFreqFNumBlock(chipClock,CHIP_FREQBASE,x,bits,blk)
// this is for volume scaling calculation.
#define VOL_SCALE_LINEAR(x,y,range) ((parent->song.ceilVolumeScaling)?((((x)*(y))+(range-1))/(range)):(((x)*(y))/(range)))
#define VOL_SCALE_LINEAR(x,y,range) ((parent->song.compatFlags.ceilVolumeScaling)?((((x)*(y))+(range-1))/(range)):(((x)*(y))/(range)))
#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)))
#define VOL_SCALE_LINEAR_BROKEN(x,y,range) ((parent->song.compatFlags.newVolumeScaling)?(VOL_SCALE_LINEAR(x,y,range)):(VOL_SCALE_LOG(x,y,range)))
#define VOL_SCALE_LOG_BROKEN(x,y,range) ((parent->song.compatFlags.newVolumeScaling)?(VOL_SCALE_LOG(x,y,range)):(VOL_SCALE_LINEAR(x,y,range)))
// these are here for convenience.
// it is encouraged to use these, since you get an exact value this way.
@ -1098,7 +1098,7 @@ class DivDispatch {
if ((x)<(xMin)) (x)=(xMin); \
if ((x)>(xMax)) (x)=(xMax);
#define NEW_ARP_STRAT (parent->song.linearPitch && !parent->song.oldArpStrategy)
#define NEW_ARP_STRAT (parent->song.compatFlags.linearPitch && !parent->song.compatFlags.oldArpStrategy)
#define HACKY_LEGATO_MESS chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode && !NEW_ARP_STRAT
#endif

View file

@ -345,7 +345,6 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
((DivPlatformArcade*)dispatch)->setYMFM(eng->getConfInt("arcadeCore",0)==0);
}
break;
case DIV_SYSTEM_YM2610:
case DIV_SYSTEM_YM2610_FULL:
dispatch=new DivPlatformYM2610;
if (isRender) {
@ -354,7 +353,6 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
((DivPlatformYM2610*)dispatch)->setCombo(eng->getConfInt("opnbCore",1));
}
break;
case DIV_SYSTEM_YM2610_EXT:
case DIV_SYSTEM_YM2610_FULL_EXT:
dispatch=new DivPlatformYM2610Ext;
if (isRender) {
@ -599,7 +597,6 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
dispatch=new DivPlatformQSound;
break;
case DIV_SYSTEM_SEGAPCM:
case DIV_SYSTEM_SEGAPCM_COMPAT:
dispatch=new DivPlatformSegaPCM;
break;
case DIV_SYSTEM_X1_010:

File diff suppressed because it is too large Load diff

View file

@ -27,6 +27,7 @@
#include "export.h"
#include "dataErrors.h"
#include "safeWriter.h"
#include "sysDef.h"
#include "cmdStream.h"
#include "filePlayer.h"
#include "../audio/taAudio.h"
@ -55,8 +56,8 @@ class DivWorkPool;
#define DIV_UNSTABLE
#define DIV_VERSION "dev239"
#define DIV_ENGINE_VERSION 239
#define DIV_VERSION "dev240"
#define DIV_ENGINE_VERSION 240
// for imports
#define DIV_VERSION_MOD 0xff01
#define DIV_VERSION_FC 0xff02
@ -332,129 +333,6 @@ struct DivEffectContainer {
}
};
typedef int EffectValConversion(unsigned char,unsigned char);
struct EffectHandler {
DivDispatchCmds dispatchCmd;
const char* description;
EffectValConversion* val;
EffectValConversion* val2;
EffectHandler(
DivDispatchCmds dispatchCmd_,
const char* description_,
EffectValConversion val_=NULL,
EffectValConversion val2_=NULL
):
dispatchCmd(dispatchCmd_),
description(description_),
val(val_),
val2(val2_) {}
};
struct DivDoNotHandleEffect {
};
typedef std::unordered_map<unsigned char,const EffectHandler> EffectHandlerMap;
struct DivSysDef {
const char* name;
const char* nameJ;
const char* description;
unsigned char id;
unsigned char id_DMF;
int channels;
bool isFM, isSTD, isCompound;
// width 0: variable
// height 0: no wavetable support
unsigned short waveWidth, waveHeight;
unsigned int vgmVersion;
unsigned int sampleFormatMask;
const char* chanNames[DIV_MAX_CHANS];
const char* chanShortNames[DIV_MAX_CHANS];
int chanTypes[DIV_MAX_CHANS];
// 0: primary
// 1: alternate (usually PCM)
DivInstrumentType chanInsType[DIV_MAX_CHANS][2];
const EffectHandlerMap effectHandlers;
const EffectHandlerMap postEffectHandlers;
const EffectHandlerMap preEffectHandlers;
DivSysDef(
const char* sysName, const char* sysNameJ, unsigned char fileID, unsigned char fileID_DMF, int chans,
bool isFMChip, bool isSTDChip, unsigned int vgmVer, bool compound, unsigned int formatMask, unsigned short waveWid, unsigned short waveHei,
const char* desc,
std::initializer_list<const char*> chNames,
std::initializer_list<const char*> chShortNames,
std::initializer_list<int> chTypes,
std::initializer_list<DivInstrumentType> chInsType1,
std::initializer_list<DivInstrumentType> chInsType2={},
const EffectHandlerMap fxHandlers_={},
const EffectHandlerMap postFxHandlers_={},
const EffectHandlerMap preFxHandlers_={}):
name(sysName),
nameJ(sysNameJ),
description(desc),
id(fileID),
id_DMF(fileID_DMF),
channels(chans),
isFM(isFMChip),
isSTD(isSTDChip),
isCompound(compound),
waveWidth(waveWid),
waveHeight(waveHei),
vgmVersion(vgmVer),
sampleFormatMask(formatMask),
effectHandlers(fxHandlers_),
postEffectHandlers(postFxHandlers_),
preEffectHandlers(preFxHandlers_) {
memset(chanNames,0,DIV_MAX_CHANS*sizeof(void*));
memset(chanShortNames,0,DIV_MAX_CHANS*sizeof(void*));
memset(chanTypes,0,DIV_MAX_CHANS*sizeof(int));
for (int i=0; i<DIV_MAX_CHANS; i++) {
chanInsType[i][0]=DIV_INS_NULL;
chanInsType[i][1]=DIV_INS_NULL;
}
int index=0;
for (const char* i: chNames) {
chanNames[index++]=i;
if (index>=DIV_MAX_CHANS) break;
}
index=0;
for (const char* i: chShortNames) {
chanShortNames[index++]=i;
if (index>=DIV_MAX_CHANS) break;
}
index=0;
for (int i: chTypes) {
chanTypes[index++]=i;
if (index>=DIV_MAX_CHANS) break;
}
index=0;
for (DivInstrumentType i: chInsType1) {
chanInsType[index++][0]=i;
if (index>=DIV_MAX_CHANS) break;
}
index=0;
for (DivInstrumentType i: chInsType2) {
chanInsType[index++][1]=i;
if (index>=DIV_MAX_CHANS) break;
}
}
};
enum DivChanTypes {
DIV_CH_FM=0,
DIV_CH_PULSE=1,
DIV_CH_NOISE=2,
DIV_CH_WAVE=3,
DIV_CH_PCM=4,
DIV_CH_OP=5
};
extern const char* cmdName[];
class DivEngine {
@ -463,7 +341,6 @@ class DivEngine {
TAAudioDesc want, got;
String exportPath;
std::thread* exportThread;
int chans;
bool configLoaded;
bool active;
bool lowQuality;
@ -546,7 +423,6 @@ class DivEngine {
std::vector<String> midiIns;
std::vector<String> midiOuts;
std::vector<DivCommand> cmdStream;
std::vector<DivInstrumentType> possibleInsTypes;
std::vector<DivEffectContainer> effectInst;
std::vector<int> curChanMask;
static DivSysDef* sysDefs[DIV_MAX_CHIP_DEFS];
@ -625,7 +501,6 @@ class DivEngine {
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
bool perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal);
bool perSystemPreEffect(int ch, unsigned char effect, unsigned char effectVal);
void recalcChans();
void reset();
void playSub(bool preserveDrift, int goalRow=0);
void runMidiClock(int totalCycles=1);
@ -688,6 +563,7 @@ class DivEngine {
void copyChannel(int src, int dest);
void swapChannels(int src, int dest);
void stompChannel(int ch);
bool sysChanCountChange(int firstChan, int before, int after);
// recalculate patchbay (UNSAFE)
void recalcPatchbay();
@ -701,16 +577,6 @@ class DivEngine {
void swapSystemUnsafe(int src, int dest, bool preserveOrder=true);
// move an asset
void moveAsset(std::vector<DivAssetDir>& dir, int before, int after);
// remove an asset
void removeAsset(std::vector<DivAssetDir>& dir, int entry);
// read/write asset dir
void putAssetDirData(SafeWriter* w, std::vector<DivAssetDir>& dir);
DivDataErrors readAssetDirData(SafeReader& reader, std::vector<DivAssetDir>& dir);
// add every export method here
friend class DivROMExport;
friend class DivExportAmigaValidation;
@ -726,10 +592,6 @@ class DivEngine {
DivChannelData* curPat;
DivSubSong* curSubSong;
DivInstrument* tempIns;
DivSystem sysOfChan[DIV_MAX_CHANS];
int dispatchOfChan[DIV_MAX_CHANS];
int dispatchChanOfChan[DIV_MAX_CHANS];
int dispatchFirstChan[DIV_MAX_CHANS];
bool keyHit[DIV_MAX_CHANS];
float* oscBuf[DIV_MAX_OUTPUTS];
float oscSize;
@ -819,9 +681,6 @@ class DivEngine {
// convert old flags
static void convertOldFlags(unsigned int oldFlags, DivConfig& newFlags, DivSystem sys);
// check whether an asset directory is complete (UNSAFE)
void checkAssetDir(std::vector<DivAssetDir>& dir, size_t entries);
// benchmark (returns time in seconds)
double benchmarkPlayback();
double benchmarkSeek();
@ -966,7 +825,7 @@ class DivEngine {
const char* getSystemNameJ(DivSystem sys);
// get sys definition
const DivSysDef* getSystemDef(DivSystem sys);
static const DivSysDef* getSystemDef(DivSystem sys);
// get ROM export definition
const DivROMExportDef* getROMExportDef(DivROMExportOptions opt);
@ -1356,6 +1215,9 @@ class DivEngine {
// change system
bool changeSystem(int index, DivSystem which, bool preserveOrder=true);
// set system channel count
bool setSystemChans(int index, int ch, bool preserveOrder=true);
// add system
bool addSystem(DivSystem which);
@ -1469,7 +1331,6 @@ class DivEngine {
DivEngine():
output(NULL),
exportThread(NULL),
chans(0),
configLoaded(false),
active(false),
lowQuality(false),
@ -1604,10 +1465,6 @@ class DivEngine {
mu5ROM(NULL) {
memset(isMuted,0,DIV_MAX_CHANS*sizeof(bool));
memset(keyHit,0,DIV_MAX_CHANS*sizeof(bool));
memset(dispatchFirstChan,0,DIV_MAX_CHANS*sizeof(int));
memset(dispatchChanOfChan,0,DIV_MAX_CHANS*sizeof(int));
memset(dispatchOfChan,0,DIV_MAX_CHANS*sizeof(int));
memset(sysOfChan,0,DIV_MAX_CHANS*sizeof(int));
memset(vibTable,0,64*sizeof(short));
memset(tremTable,0,128*sizeof(short));
memset(effectSlotMap,-1,4096*sizeof(short));

View file

@ -91,7 +91,7 @@ void DivExportAmigaValidation::run() {
size_t lastTick=0;
//bool writeLoop=false;
int loopPos=-1;
for (int i=0; i<e->chans; i++) {
for (int i=0; i<e->song.chans; i++) {
e->chan[i].wentThroughNote=false;
e->chan[i].goneThroughNote=false;
}

View file

@ -172,56 +172,56 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
// compatibility flags
if (!getConfInt("noDMFCompat",0)) {
ds.limitSlides=true;
ds.linearPitch=1;
ds.loopModality=0;
ds.properNoiseLayout=false;
ds.waveDutyIsVol=false;
ds.compatFlags.limitSlides=true;
ds.compatFlags.linearPitch=1;
ds.compatFlags.loopModality=0;
ds.compatFlags.properNoiseLayout=false;
ds.compatFlags.waveDutyIsVol=false;
// TODO: WHAT?! geodude.dmf fails when this is true
// but isn't that how Defle behaves???
ds.resetMacroOnPorta=false;
ds.legacyVolumeSlides=true;
ds.compatibleArpeggio=true;
ds.noteOffResetsSlides=true;
ds.targetResetsSlides=true;
ds.arpNonPorta=false;
ds.algMacroBehavior=false;
ds.brokenShortcutSlides=false;
ds.ignoreDuplicateSlides=true;
ds.brokenDACMode=true;
ds.oneTickCut=false;
ds.newInsTriggersInPorta=true;
ds.arp0Reset=true;
ds.brokenSpeedSel=true;
ds.noSlidesOnFirstTick=false;
ds.rowResetsArpPos=false;
ds.ignoreJumpAtEnd=true;
ds.buggyPortaAfterSlide=true;
ds.gbInsAffectsEnvelope=true;
ds.ignoreDACModeOutsideIntendedChannel=false;
ds.e1e2AlsoTakePriority=true;
ds.fbPortaPause=true;
ds.snDutyReset=true;
ds.oldOctaveBoundary=false;
ds.noOPN2Vol=true;
ds.newVolumeScaling=false;
ds.volMacroLinger=false;
ds.brokenOutVol=true;
ds.brokenOutVol2=true;
ds.e1e2StopOnSameNote=true;
ds.brokenPortaArp=false;
ds.snNoLowPeriods=true;
ds.disableSampleMacro=true;
ds.preNoteNoEffect=true;
ds.oldDPCM=true;
ds.delayBehavior=0;
ds.jumpTreatment=2;
ds.oldAlwaysSetVolume=true;
ds.compatFlags.resetMacroOnPorta=false;
ds.compatFlags.legacyVolumeSlides=true;
ds.compatFlags.compatibleArpeggio=true;
ds.compatFlags.noteOffResetsSlides=true;
ds.compatFlags.targetResetsSlides=true;
ds.compatFlags.arpNonPorta=false;
ds.compatFlags.algMacroBehavior=false;
ds.compatFlags.brokenShortcutSlides=false;
ds.compatFlags.ignoreDuplicateSlides=true;
ds.compatFlags.brokenDACMode=true;
ds.compatFlags.oneTickCut=false;
ds.compatFlags.newInsTriggersInPorta=true;
ds.compatFlags.arp0Reset=true;
ds.compatFlags.brokenSpeedSel=true;
ds.compatFlags.noSlidesOnFirstTick=false;
ds.compatFlags.rowResetsArpPos=false;
ds.compatFlags.ignoreJumpAtEnd=true;
ds.compatFlags.buggyPortaAfterSlide=true;
ds.compatFlags.gbInsAffectsEnvelope=true;
ds.compatFlags.ignoreDACModeOutsideIntendedChannel=false;
ds.compatFlags.e1e2AlsoTakePriority=true;
ds.compatFlags.fbPortaPause=true;
ds.compatFlags.snDutyReset=true;
ds.compatFlags.oldOctaveBoundary=false;
ds.compatFlags.noOPN2Vol=true;
ds.compatFlags.newVolumeScaling=false;
ds.compatFlags.volMacroLinger=false;
ds.compatFlags.brokenOutVol=true;
ds.compatFlags.brokenOutVol2=true;
ds.compatFlags.e1e2StopOnSameNote=true;
ds.compatFlags.brokenPortaArp=false;
ds.compatFlags.snNoLowPeriods=true;
ds.compatFlags.disableSampleMacro=true;
ds.compatFlags.preNoteNoEffect=true;
ds.compatFlags.oldDPCM=true;
ds.compatFlags.delayBehavior=0;
ds.compatFlags.jumpTreatment=2;
ds.compatFlags.oldAlwaysSetVolume=true;
// 1.1 compat flags
if (ds.version>24) {
ds.waveDutyIsVol=true;
ds.legacyVolumeSlides=false;
ds.compatFlags.waveDutyIsVol=true;
ds.compatFlags.legacyVolumeSlides=false;
}
// Neo Geo detune is caused by Defle running Neo Geo at the wrong clock.
@ -256,11 +256,11 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
bool customTempo=false;
ds.subsong[0]->timeBase=reader.readC();
unsigned char oldTimeBase=reader.readC();
ds.subsong[0]->speeds.len=2;
ds.subsong[0]->speeds.val[0]=reader.readC();
ds.subsong[0]->speeds.val[0]=(unsigned char)reader.readC();
if (ds.version>0x07) {
ds.subsong[0]->speeds.val[1]=reader.readC();
ds.subsong[0]->speeds.val[1]=(unsigned char)reader.readC();
bool pal=reader.readC();
ds.subsong[0]->hz=pal?60:50;
customTempo=reader.readC();
@ -317,7 +317,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
}
if (ds.system[0]==DIV_SYSTEM_YMU759) {
switch (ds.subsong[0]->timeBase) {
switch (oldTimeBase) {
case 0:
ds.subsong[0]->hz=248;
break;
@ -340,8 +340,10 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
ds.subsong[0]->hz=248;
break;
}
ds.subsong[0]->timeBase=0;
addWarning("Yamaha YMU759 emulation is incomplete! please migrate your song to the OPL3 system.");
} else {
ds.subsong[0]->speeds.val[0]*=(oldTimeBase+1);
ds.subsong[0]->speeds.val[1]*=(oldTimeBase+1);
}
logV("%x",reader.tell());
@ -395,7 +397,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
if (ds.system[0]==DIV_SYSTEM_C64_8580 || ds.system[0]==DIV_SYSTEM_C64_6581) {
ins->type=DIV_INS_C64;
}
if (ds.system[0]==DIV_SYSTEM_YM2610 || ds.system[0]==DIV_SYSTEM_YM2610_EXT
if (ds.system[0]==DIV_SYSTEM_YM2610_CRAP || ds.system[0]==DIV_SYSTEM_YM2610_CRAP_EXT
|| ds.system[0]==DIV_SYSTEM_YM2610_FULL || ds.system[0]==DIV_SYSTEM_YM2610_FULL_EXT
|| ds.system[0]==DIV_SYSTEM_YM2610B || ds.system[0]==DIV_SYSTEM_YM2610B_EXT) {
if (!mode) {
@ -627,7 +629,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
}
// piece of crap offset by 1
if (ds.system[0]==DIV_SYSTEM_YM2610 || ds.system[0]==DIV_SYSTEM_YM2610_EXT) {
if (ds.system[0]==DIV_SYSTEM_YM2610_CRAP || ds.system[0]==DIV_SYSTEM_YM2610_CRAP_EXT) {
ins->std.waveMacro.val[j]++;
}
}
@ -1167,15 +1169,30 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
ds.systemFlags[0].set("brokenPitch",true);
}
ds.initDefaultSystemChans();
// flatten 5-channel SegaPCM and Neo Geo CD
for (int i=0; i<ds.systemLen; i++) {
if (ds.system[i]==DIV_SYSTEM_SEGAPCM_COMPAT) {
ds.system[i]=DIV_SYSTEM_SEGAPCM;
} else if (ds.system[i]==DIV_SYSTEM_YM2610_CRAP) {
ds.system[i]=DIV_SYSTEM_YM2610_FULL;
} else if (ds.system[i]==DIV_SYSTEM_YM2610_CRAP_EXT) {
ds.system[i]=DIV_SYSTEM_YM2610_FULL_EXT;
}
}
ds.systemName=getSongSystemLegacyName(ds,!getConfInt("noMultiSystem",0));
ds.recalcChans();
if (active) quitDispatch();
BUSY_BEGIN_SOFT;
saveLock.lock();
song.unload();
song=ds;
hasLoadedSomething=true;
changeSong(0);
recalcChans();
// always convert to normal sample mode (I have no idea how will I do export)
convertLegacySampleMode();
saveLock.unlock();
@ -1205,6 +1222,7 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
lastError="invalid version to save in! this is a bug!";
return NULL;
}
int actualChans=song.chans;
// check whether system is compound
bool isFlat=false;
if (song.systemLen==2) {
@ -1214,8 +1232,10 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
if (song.system[0]==DIV_SYSTEM_YM2612_EXT && song.system[1]==DIV_SYSTEM_SMS) {
isFlat=true;
}
if (song.system[0]==DIV_SYSTEM_YM2151 && song.system[1]==DIV_SYSTEM_SEGAPCM_COMPAT) {
if (song.system[0]==DIV_SYSTEM_YM2151 && song.system[1]==DIV_SYSTEM_SEGAPCM) {
isFlat=true;
addWarning("only first 5 channels of SegaPCM.");
actualChans=13;
}
if (song.system[0]==DIV_SYSTEM_SMS && song.system[1]==DIV_SYSTEM_OPLL) {
isFlat=true;
@ -1231,6 +1251,10 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
addWarning("your song will sound different. I am not going to bother adding further compatibility.");
}
}
if (song.system[0]==DIV_SYSTEM_YM2610_FULL || song.system[0]==DIV_SYSTEM_YM2610_FULL_EXT) {
addWarning("ADPCM-B not supported.");
actualChans--;
}
// fail if more than one system
if (!isFlat && song.systemLen!=1) {
logE("cannot save multiple systems in this format!");
@ -1289,7 +1313,7 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
lastError="maximum number of wavetables in .dmf is 64";
return NULL;
}
for (int i=0; i<chans; i++) {
for (int i=0; i<actualChans; i++) {
for (int j=0; j<curSubSong->ordersLen; j++) {
if (curOrders->ord[i][j]>0x7f) {
logE("order %d, %d is out of range (0-127)!",i,j);
@ -1316,7 +1340,7 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
} else if (song.system[0]==DIV_SYSTEM_YM2612_EXT && song.system[1]==DIV_SYSTEM_SMS) {
w->writeC(systemToFileDMF(DIV_SYSTEM_GENESIS_EXT));
sys=DIV_SYSTEM_GENESIS_EXT;
} else if (song.system[0]==DIV_SYSTEM_YM2151 && song.system[1]==DIV_SYSTEM_SEGAPCM_COMPAT) {
} else if (song.system[0]==DIV_SYSTEM_YM2151 && song.system[1]==DIV_SYSTEM_SEGAPCM) {
w->writeC(systemToFileDMF(DIV_SYSTEM_ARCADE));
sys=DIV_SYSTEM_ARCADE;
} else if (song.system[0]==DIV_SYSTEM_SMS && song.system[1]==DIV_SYSTEM_OPLL) {
@ -1331,6 +1355,12 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
} else if (song.system[0]==DIV_SYSTEM_AY8910 && song.system[1]==DIV_SYSTEM_SCC) {
w->writeC(systemToFileDMF(DIV_SYSTEM_MSX2));
sys=DIV_SYSTEM_MSX2;
} else if (song.system[0]==DIV_SYSTEM_YM2610_FULL) {
w->writeC(systemToFileDMF(DIV_SYSTEM_YM2610_CRAP));
sys=DIV_SYSTEM_YM2610_CRAP;
} else if (song.system[0]==DIV_SYSTEM_YM2610_FULL_EXT) {
w->writeC(systemToFileDMF(DIV_SYSTEM_YM2610_CRAP_EXT));
sys=DIV_SYSTEM_YM2610_CRAP_EXT;
} else {
w->writeC(systemToFileDMF(song.system[0]));
sys=song.system[0];
@ -1344,7 +1374,7 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
int intHz=curSubSong->hz;
w->writeC(curSubSong->timeBase);
w->writeC(0);
w->writeC(curSubSong->speeds.val[0]);
w->writeC((curSubSong->speeds.len>=2)?curSubSong->speeds.val[1]:curSubSong->speeds.val[0]);
w->writeC((intHz<=53)?0:1);
@ -1356,7 +1386,7 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
w->writeI(curSubSong->patLen);
w->writeC(curSubSong->ordersLen);
for (int i=0; i<chans; i++) {
for (int i=0; i<actualChans; i++) {
for (int j=0; j<curSubSong->ordersLen; j++) {
w->writeC(curOrders->ord[i][j]);
if (version>=25) {
@ -1425,8 +1455,8 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
case DIV_SYSTEM_PCE:
i->type=DIV_INS_PCE;
break;
case DIV_SYSTEM_YM2610:
case DIV_SYSTEM_YM2610_EXT:
case DIV_SYSTEM_YM2610_FULL:
case DIV_SYSTEM_YM2610_FULL_EXT:
i->type=DIV_INS_AY;
break;
default:
@ -1578,7 +1608,7 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
w->writeC(realWaveMacroLen);
for (int j=0; j<realWaveMacroLen; j++) {
// piece of crap offset by 1
if (song.system[0]==DIV_SYSTEM_YM2610 || song.system[0]==DIV_SYSTEM_YM2610_EXT) {
if (song.system[0]==DIV_SYSTEM_YM2610_FULL || song.system[0]==DIV_SYSTEM_YM2610_FULL_EXT) {
w->writeI(i->std.waveMacro.val[j]-1);
} else {
w->writeI(i->std.waveMacro.val[j]);
@ -1642,7 +1672,7 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
bool relWarning=false;
for (int i=0; i<getChannelCount(sys); i++) {
for (int i=0; i<actualChans; i++) {
short note, octave;
w->writeC(curPat[i].effectCols);
@ -1671,13 +1701,13 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
alwaysConvert=true;
}
break;
case DIV_SYSTEM_YM2610:
case DIV_SYSTEM_YM2610_CRAP:
if (i>=7) {
convertSampleUsage=true;
alwaysConvert=true;
}
break;
case DIV_SYSTEM_YM2610_EXT:
case DIV_SYSTEM_YM2610_CRAP_EXT:
if (i>=10) {
convertSampleUsage=true;
alwaysConvert=true;

View file

@ -147,12 +147,12 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
DivSong ds;
ds.tuning=436.0;
ds.version=DIV_VERSION_FC;
//ds.linearPitch=0;
//ds.pitchMacroIsLinear=false;
//ds.noSlidesOnFirstTick=true;
//ds.rowResetsArpPos=true;
ds.pitchSlideSpeed=8;
ds.ignoreJumpAtEnd=false;
//ds.compatFlags.linearPitch=0;
//ds.compatFlags.pitchMacroIsLinear=false;
//ds.compatFlags.noSlidesOnFirstTick=true;
//ds.compatFlags.rowResetsArpPos=true;
ds.compatFlags.pitchSlideSpeed=8;
ds.compatFlags.ignoreJumpAtEnd=false;
// load here
if (!reader.seek(0,SEEK_SET)) {
@ -664,13 +664,16 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
ds.subsong[0]->optimizePatterns();
ds.subsong[0]->rearrangePatterns();
ds.initDefaultSystemChans();
ds.recalcChans();
if (active) quitDispatch();
BUSY_BEGIN_SOFT;
saveLock.lock();
song.unload();
song=ds;
hasLoadedSomething=true;
changeSong(0);
recalcChans();
saveLock.unlock();
BUSY_END;
if (active) {

View file

@ -495,7 +495,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
ds.subsong.clear();
ds.linearPitch = 0;
ds.compatFlags.linearPitch = 0;
unsigned int pal = 0;
@ -654,6 +654,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
int curr_chan = 0;
int map_ch = 0;
ds.systemChans[systemID]=5;
ds.system[systemID++] = DIV_SYSTEM_NES;
ds.systemFlags[0].set("resetSweep",true); // FamiTracker behavior
@ -668,6 +669,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
if (expansions & 1) {
ds.systemChans[systemID]=3;
ds.system[systemID++] = DIV_SYSTEM_VRC6;
for (int ch = 0; ch < 3; ch++) {
@ -685,6 +687,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
vrc6_saw_chan = map_ch - 1;
}
if (expansions & 8) {
ds.systemChans[systemID]=3;
ds.system[systemID++] = DIV_SYSTEM_MMC5;
for (int ch = 0; ch < (eft ? 3 : 2); ch++) {
@ -707,6 +710,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
if (expansions & 16) {
ds.system[systemID] = DIV_SYSTEM_N163;
ds.systemFlags[systemID].set("channels", (int)n163Chans - 1);
ds.systemChans[systemID]=CLAMP(n163Chans,1,8);
systemID++;
for (int ch = 0; ch < (int)n163Chans; ch++) {
@ -716,12 +720,13 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
map_ch++;
}
for (int ch = 0; ch < (8 - (int)n163Chans); ch++) {
/*for (int ch = 0; ch < (8 - (int)n163Chans); ch++) {
map_channels[curr_chan] = map_ch; // do not populate and skip the missing N163 channels!
map_ch++;
}
}*/
}
if (expansions & 4) {
ds.systemChans[systemID]=1;
ds.system[systemID++] = DIV_SYSTEM_FDS;
map_channels[curr_chan] = map_ch;
@ -730,6 +735,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
map_ch++;
}
if (expansions & 2) {
ds.systemChans[systemID]=6;
ds.system[systemID++] = DIV_SYSTEM_VRC7;
for (int ch = 0; ch < 6; ch++) {
@ -741,6 +747,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
if (expansions & 32) {
ds.system[systemID] = DIV_SYSTEM_AY8910;
ds.systemChans[systemID]=3;
ds.systemFlags[systemID++].set("chipType", 2); // Sunsoft 5B
for (int ch = 0; ch < 3; ch++) {
@ -751,6 +758,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
}
if (expansions & 64) {
ds.systemChans[systemID]=3;
ds.system[systemID++] = DIV_SYSTEM_AY8930;
for (int ch = 0; ch < 3; ch++) {
@ -761,6 +769,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
}
if (expansions & 128) {
ds.systemChans[systemID]=6;
ds.system[systemID++] = DIV_SYSTEM_SAA1099;
for (int ch = 0; ch < 6; ch++) {
@ -770,6 +779,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
}
if (expansions & 256) {
ds.systemChans[systemID]=5;
ds.system[systemID++] = DIV_SYSTEM_5E01;
for (int ch = 0; ch < 5; ch++) {
@ -779,6 +789,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
}
if (expansions & 512) {
ds.systemChans[systemID]=3;
ds.system[systemID++] = DIV_SYSTEM_C64_6581;
for (int ch = 0; ch < 3; ch++) {
@ -788,6 +799,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
}
if (expansions & 1024) {
ds.systemChans[systemID]=3;
ds.system[systemID++] = DIV_SYSTEM_C64_8580;
for (int ch = 0; ch < 3; ch++) {
@ -797,6 +809,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
}
if (expansions & 2048) {
ds.systemChans[systemID]=4;
ds.system[systemID++] = DIV_SYSTEM_POKEY;
for (int ch = 0; ch < 4; ch++) {
@ -817,13 +830,8 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
calcChans--; // no PCM channel for MMC5 in famitracker
}
calcChans += getChannelCount(ds.system[i]);
total_chans += getChannelCount(ds.system[i]);
if (ds.system[i] == DIV_SYSTEM_N163) {
calcChans -= getChannelCount(ds.system[i]);
calcChans += (int)n163Chans;
}
calcChans += ds.systemChans[i];
total_chans += ds.systemChans[i];
}
if (calcChans != tchans) {
// TODO: would ignore trigger CVE? too bad if so!
@ -2370,7 +2378,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
CHECK_BLOCK_VERSION(3);
unsigned int linear_pitch = reader.readI();
ds.linearPitch = linear_pitch == 0 ? 0 : 1;
ds.compatFlags.linearPitch = linear_pitch == 0 ? 0 : 1;
if (blockVersion >= 2) {
int fineTuneCents = reader.readC() * 100;
@ -2802,13 +2810,15 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
}
ds.recalcChans();
if (active) quitDispatch();
BUSY_BEGIN_SOFT;
saveLock.lock();
song.unload();
song=ds;
hasLoadedSomething=true;
changeSong(0);
recalcChans();
saveLock.unlock();
BUSY_END;
if (active) {

File diff suppressed because it is too large Load diff

View file

@ -219,10 +219,10 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
try {
DivSong ds;
ds.version=DIV_VERSION_IT;
ds.noSlidesOnFirstTick=true;
ds.rowResetsArpPos=true;
ds.ignoreJumpAtEnd=false;
ds.pitchSlideSpeed=8;
ds.compatFlags.noSlidesOnFirstTick=true;
ds.compatFlags.rowResetsArpPos=true;
ds.compatFlags.ignoreJumpAtEnd=false;
ds.compatFlags.pitchSlideSpeed=8;
logV("Impulse Tracker module");
@ -277,9 +277,9 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
}
if (flags&8) {
ds.linearPitch=1;
ds.compatFlags.linearPitch=1;
} else {
ds.linearPitch=0;
ds.compatFlags.linearPitch=0;
}
unsigned char globalVol=reader.readC();
@ -1619,12 +1619,6 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
logV("maxChan: %d",maxChan);
// set channel visibility
for (int i=maxChan; i<((maxChan+32)&(~31)); i++) {
ds.subsong[0]->chanShow[i]=false;
ds.subsong[0]->chanShowChanOsc[i]=false;
}
// copy patterns to the rest of subsongs
int copiesMade=0;
for (size_t i=1; i<ds.subsong.size(); i++) {
@ -1664,10 +1658,13 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
}
// set systems
int chansToCount=maxChan;
for (int i=0; i<(maxChan+32)>>5; i++) {
ds.system[i]=DIV_SYSTEM_ES5506;
ds.systemChans[i]=MIN(32,chansToCount);
chansToCount-=ds.systemChans[i];
ds.systemFlags[i].set("amigaVol",true);
if (!ds.linearPitch) {
if (!ds.compatFlags.linearPitch) {
ds.systemFlags[i].set("amigaPitch",true);
}
}
@ -1675,7 +1672,8 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
ds.systemName="PC";
// find subsongs
ds.findSubSongs(maxChan);
ds.recalcChans();
ds.findSubSongs();
// populate subsongs with default panning values
for (size_t i=0; i<ds.subsong.size(); i++) {
@ -1707,8 +1705,8 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
saveLock.lock();
song.unload();
song=ds;
hasLoadedSomething=true;
changeSong(0);
recalcChans();
saveLock.unlock();
BUSY_END;
if (active) {

View file

@ -41,11 +41,11 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
DivSong ds;
ds.tuning=436.0;
ds.version=DIV_VERSION_MOD;
ds.linearPitch=0;
ds.noSlidesOnFirstTick=true;
ds.rowResetsArpPos=true;
ds.ignoreJumpAtEnd=false;
ds.delayBehavior=0;
ds.compatFlags.linearPitch=0;
ds.compatFlags.noSlidesOnFirstTick=true;
ds.compatFlags.rowResetsArpPos=true;
ds.compatFlags.ignoreJumpAtEnd=false;
ds.compatFlags.delayBehavior=0;
int insCount=31;
bool bypassLimits=false;
@ -431,15 +431,17 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
ds.insLen=ds.ins.size();
// find subsongs
ds.findSubSongs(chCount);
ds.initDefaultSystemChans();
ds.recalcChans();
ds.findSubSongs();
if (active) quitDispatch();
BUSY_BEGIN_SOFT;
saveLock.lock();
song.unload();
song=ds;
hasLoadedSomething=true;
changeSong(0);
recalcChans();
saveLock.unlock();
BUSY_END;
if (active) {

View file

@ -79,12 +79,12 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
try {
DivSong ds;
ds.version=DIV_VERSION_S3M;
ds.linearPitch=0;
ds.pitchMacroIsLinear=false;
ds.noSlidesOnFirstTick=true;
ds.rowResetsArpPos=true;
ds.ignoreJumpAtEnd=false;
ds.pitchSlideSpeed=12;
ds.compatFlags.linearPitch=0;
ds.compatFlags.pitchMacroIsLinear=false;
ds.compatFlags.noSlidesOnFirstTick=true;
ds.compatFlags.rowResetsArpPos=true;
ds.compatFlags.ignoreJumpAtEnd=false;
ds.compatFlags.pitchSlideSpeed=12;
logV("Scream Tracker 3 module");
@ -345,6 +345,7 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
ds.systemName="PC";
if (hasPCM) {
ds.system[ds.systemLen]=DIV_SYSTEM_ES5506;
ds.systemChans[ds.systemLen]=32; // for now
ds.systemVol[ds.systemLen]=(float)globalVol/64.0;
ds.systemPan[ds.systemLen]=0;
ds.systemFlags[ds.systemLen].set("volScale",3900);
@ -354,6 +355,7 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
}
if (hasFM) {
ds.system[ds.systemLen]=opl2 ? DIV_SYSTEM_OPL2 : DIV_SYSTEM_OPL3;
ds.systemChans[ds.systemLen]=opl2?9:18; // for now
ds.systemVol[ds.systemLen]=1.0f;
ds.systemPan[ds.systemLen]=0;
ds.systemLen++;
@ -1179,7 +1181,8 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
}
// find subsongs
ds.findSubSongs(DIV_MAX_CHANS);
ds.recalcChans();
ds.findSubSongs();
// populate subsongs with default panning values
if (masterVol&128) { // only in stereo mode
@ -1214,8 +1217,8 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
saveLock.lock();
song.unload();
song=ds;
hasLoadedSomething=true;
changeSong(0);
recalcChans();
saveLock.unlock();
BUSY_END;
if (active) {

View file

@ -296,13 +296,12 @@ SafeWriter* DivEngine::saveText(bool separatePatterns) {
}
w->writeText("\n");
w->writeText(fmt::sprintf("- virtual tempo: %d/%d\n",s->virtualTempoN,s->virtualTempoD));
w->writeText(fmt::sprintf("- time base: %d\n",s->timeBase));
w->writeText(fmt::sprintf("- pattern length: %d\n",s->patLen));
w->writeText(fmt::sprintf("\norders:\n```\n"));
for (int j=0; j<s->ordersLen; j++) {
w->writeText(fmt::sprintf("%.2X |",j));
for (int k=0; k<chans; k++) {
for (int k=0; k<song.chans; k++) {
w->writeText(fmt::sprintf(" %.2X",s->orders.ord[k][j]));
}
w->writeText("\n");
@ -318,7 +317,7 @@ SafeWriter* DivEngine::saveText(bool separatePatterns) {
for (int k=0; k<s->patLen; k++) {
w->writeText(fmt::sprintf("%.2X ",k));
for (int l=0; l<chans; l++) {
for (int l=0; l<song.chans; l++) {
DivPattern* p=s->pat[l].getPattern(s->orders.ord[l][j],false);
short note, octave;
noteToSplitNote(p->newData[k][DIV_PAT_NOTE],note,octave);

View file

@ -551,7 +551,7 @@ bool DivEngine::loadTFMv1(unsigned char* file, size_t len) {
ds.systemLen=1;
ds.system[0]=DIV_SYSTEM_YM2612;
ds.loopModality=1;
ds.compatFlags.loopModality=1;
unsigned char speed=reader.readCNoRLE();
unsigned char interleaveFactor=reader.readCNoRLE();
@ -704,13 +704,15 @@ bool DivEngine::loadTFMv1(unsigned char* file, size_t len) {
info.loopPos=loopPos;
TFMParsePattern(info);
ds.recalcChans();
if (active) quitDispatch();
BUSY_BEGIN_SOFT;
saveLock.lock();
song.unload();
song=ds;
hasLoadedSomething=true;
changeSong(0);
recalcChans();
saveLock.unlock();
BUSY_END;
if (active) {
@ -744,7 +746,7 @@ bool DivEngine::loadTFMv2(unsigned char* file, size_t len) {
ds.systemLen=1;
ds.system[0]=DIV_SYSTEM_YM2612;
ds.loopModality=1;
ds.compatFlags.loopModality=1;
unsigned char magic[8]={0};
@ -904,13 +906,16 @@ bool DivEngine::loadTFMv2(unsigned char* file, size_t len) {
info.loopPos=loopPos;
TFMParsePattern(info);
ds.initDefaultSystemChans();
ds.recalcChans();
if (active) quitDispatch();
BUSY_BEGIN_SOFT;
saveLock.lock();
song.unload();
song=ds;
hasLoadedSomething=true;
changeSong(0);
recalcChans();
saveLock.unlock();
BUSY_END;
if (active) {

View file

@ -207,12 +207,12 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
try {
DivSong ds;
ds.version=DIV_VERSION_XM;
//ds.linearPitch=0;
//ds.pitchMacroIsLinear=false;
ds.noSlidesOnFirstTick=true;
ds.rowResetsArpPos=true;
ds.ignoreJumpAtEnd=false;
ds.pitchSlideSpeed=8;
//ds.compatFlags.linearPitch=0;
//ds.compatFlags.pitchMacroIsLinear=false;
ds.compatFlags.noSlidesOnFirstTick=true;
ds.compatFlags.rowResetsArpPos=true;
ds.compatFlags.ignoreJumpAtEnd=false;
ds.compatFlags.pitchSlideSpeed=8;
logV("Extended Module");
@ -251,7 +251,7 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
unsigned short totalChans=reader.readS();
unsigned short patCount=reader.readS();
ds.insLen=(unsigned short)reader.readS();
ds.linearPitch=(reader.readS()&1)?1:0;
ds.compatFlags.linearPitch=(reader.readS()&1)?1:0;
ds.subsong[0]->speeds.val[0]=reader.readS();
ds.subsong[0]->speeds.len=1;
double bpm=(unsigned short)reader.readS();
@ -301,10 +301,13 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
}
}
int chansToCount=totalChans;
for (int i=0; i<(totalChans+31)>>5; i++) {
ds.system[i]=DIV_SYSTEM_ES5506;
ds.systemChans[i]=MIN(32,chansToCount);
chansToCount-=ds.systemChans[i];
ds.systemFlags[i].set("amigaVol",true);
ds.systemFlags[i].set("amigaPitch",(ds.linearPitch==0));
ds.systemFlags[i].set("amigaPitch",(ds.compatFlags.linearPitch==0));
ds.systemFlags[i].set("volScale",3900);
}
ds.systemLen=(totalChans+31)>>5;
@ -1370,22 +1373,17 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
return false;
}
// set channel visibility
for (int i=totalChans; i<((totalChans+32)&(~31)); i++) {
ds.subsong[0]->chanShow[i]=false;
ds.subsong[0]->chanShowChanOsc[i]=false;
}
// find subsongs
ds.findSubSongs(totalChans);
ds.recalcChans();
ds.findSubSongs();
if (active) quitDispatch();
BUSY_BEGIN_SOFT;
saveLock.lock();
song.unload();
song=ds;
hasLoadedSomething=true;
changeSong(0);
recalcChans();
saveLock.unlock();
BUSY_END;
if (active) {

View file

@ -22,6 +22,7 @@
#include "engine.h"
#include <fmt/printf.h>
// TODO: this function could be in DivSong instead
bool DivEngine::convertLegacySampleMode() {
logD("converting legacy sample mode...");
int legacyInsInit=-1;
@ -114,7 +115,7 @@ bool DivEngine::convertLegacySampleMode() {
};
for (DivSubSong* h: song.subsong) {
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
// 0: sample off
// 1: legacy mode
// 2: normal mode
@ -125,11 +126,11 @@ bool DivEngine::convertLegacySampleMode() {
bool noteOffDisablesSampleMode=false;
bool hasLegacyToggle=false;
switch (sysOfChan[i]) {
switch (song.sysOfChan[i]) {
case DIV_SYSTEM_NES:
case DIV_SYSTEM_5E01:
// NES PCM channel (on by default)
if (dispatchChanOfChan[i]!=4) {
if (song.dispatchChanOfChan[i]!=4) {
continue;
}
sampleMode=1;
@ -137,14 +138,14 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_MMC5:
// MMC5 PCM channel
if (dispatchChanOfChan[i]!=2) {
if (song.dispatchChanOfChan[i]!=2) {
continue;
}
sampleMode=1;
break;
case DIV_SYSTEM_YM2612:
// YM2612 DAC channel
if (dispatchChanOfChan[i]!=5) {
if (song.dispatchChanOfChan[i]!=5) {
continue;
}
hasLegacyToggle=true;
@ -152,7 +153,7 @@ bool DivEngine::convertLegacySampleMode() {
case DIV_SYSTEM_YM2612_EXT:
case DIV_SYSTEM_YM2612_CSM:
// YM2612 DAC channel
if (dispatchChanOfChan[i]!=8) {
if (song.dispatchChanOfChan[i]!=8) {
continue;
}
hasLegacyToggle=true;
@ -167,20 +168,18 @@ bool DivEngine::convertLegacySampleMode() {
case DIV_SYSTEM_AY8930:
// any channel can be DAC'd
break;
case DIV_SYSTEM_YM2610:
case DIV_SYSTEM_YM2610_FULL:
// Neo Geo CD ADPCM channels
if (dispatchChanOfChan[i]<7) {
if (song.dispatchChanOfChan[i]<7) {
continue;
}
sampleMode=1;
preferredInsType=DIV_INS_ADPCMA;
preferredInsType2=DIV_INS_ADPCMB;
break;
case DIV_SYSTEM_YM2610_EXT:
case DIV_SYSTEM_YM2610_FULL_EXT:
// Neo Geo CD ADPCM channels
if (dispatchChanOfChan[i]<10) {
if (song.dispatchChanOfChan[i]<10) {
continue;
}
sampleMode=1;
@ -189,7 +188,7 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_YM2612_DUALPCM:
// DualPCM DAC
if (dispatchChanOfChan[i]<5) {
if (song.dispatchChanOfChan[i]<5) {
continue;
}
sampleMode=1;
@ -197,7 +196,7 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_YM2612_DUALPCM_EXT:
// DualPCM DAC
if (dispatchChanOfChan[i]<8 || dispatchChanOfChan[i]>9) {
if (song.dispatchChanOfChan[i]<8 || song.dispatchChanOfChan[i]>9) {
continue;
}
sampleMode=1;
@ -205,7 +204,7 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_YM2610_CSM:
// Neo Geo CD ADPCM channels
if (dispatchChanOfChan[i]<11) {
if (song.dispatchChanOfChan[i]<11) {
continue;
}
sampleMode=1;
@ -214,7 +213,7 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_YM2610B:
// ADPCM channels
if (dispatchChanOfChan[i]<9) {
if (song.dispatchChanOfChan[i]<9) {
continue;
}
sampleMode=1;
@ -223,7 +222,7 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_YM2610B_EXT:
// ADPCM channels
if (dispatchChanOfChan[i]<12) {
if (song.dispatchChanOfChan[i]<12) {
continue;
}
sampleMode=1;
@ -232,7 +231,7 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_YM2610B_CSM:
// ADPCM channels
if (dispatchChanOfChan[i]<13) {
if (song.dispatchChanOfChan[i]<13) {
continue;
}
sampleMode=1;
@ -241,7 +240,7 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_YM2608:
// ADPCM channel
if (dispatchChanOfChan[i]!=15) {
if (song.dispatchChanOfChan[i]!=15) {
continue;
}
sampleMode=1;
@ -249,7 +248,7 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_YM2608_EXT:
// ADPCM channel
if (dispatchChanOfChan[i]!=18) {
if (song.dispatchChanOfChan[i]!=18) {
continue;
}
sampleMode=1;
@ -257,14 +256,13 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_YM2608_CSM:
// ADPCM channel
if (dispatchChanOfChan[i]!=19) {
if (song.dispatchChanOfChan[i]!=19) {
continue;
}
sampleMode=1;
preferredInsType=DIV_INS_ADPCMB;
break;
case DIV_SYSTEM_SEGAPCM:
case DIV_SYSTEM_SEGAPCM_COMPAT:
// all channels can play back samples
sampleMode=1;
preferredInsType=DIV_INS_SEGAPCM;
@ -279,7 +277,7 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_Y8950:
// Y8950 ADPCM
if (dispatchChanOfChan[i]!=9) {
if (song.dispatchChanOfChan[i]!=9) {
continue;
}
sampleMode=1;
@ -287,14 +285,14 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_Y8950_DRUMS:
// Y8950 ADPCM
if (dispatchChanOfChan[i]!=11) {
if (song.dispatchChanOfChan[i]!=11) {
continue;
}
sampleMode=1;
break;
case DIV_SYSTEM_SWAN:
// PCM channel
if (dispatchChanOfChan[i]!=1) {
if (song.dispatchChanOfChan[i]!=1) {
continue;
}
noteOffDisablesSampleMode=true;
@ -302,7 +300,7 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_VRC6:
// pulse DAC mode
if (dispatchChanOfChan[i]>=2) {
if (song.dispatchChanOfChan[i]>=2) {
continue;
}
hasLegacyToggle=true;

View file

@ -43,7 +43,7 @@ void DivMacroStruct::prepare(DivInstrumentMacro& source, DivEngine* e) {
mode=source.mode;
type=(source.open>>1)&3;
activeRelease=source.open&8;
linger=(source.macroType==DIV_MACRO_VOL && e->song.volMacroLinger);
linger=(source.macroType==DIV_MACRO_VOL && e->song.compatFlags.volMacroLinger);
lfoPos=LFO_PHASE;
}

View file

@ -668,7 +668,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
chan[c.chan].writeVol=true;
}
@ -752,9 +752,9 @@ int DivPlatformAmiga::dispatch(DivCommand c) {
}
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_SAMPLE_POS:

View file

@ -260,7 +260,7 @@ void DivPlatformArcade::tick(bool sysTick) {
} else {
rWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|((chan[i].chVolL&1)<<6)|((chan[i].chVolR&1)<<7));
}
if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) {
if (!parent->song.compatFlags.algMacroBehavior) for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
if (isMuted[i] || !op.enable) {
@ -379,7 +379,7 @@ void DivPlatformArcade::tick(bool sysTick) {
for (int i=0; i<8; i++) {
if (chan[i].freqChanged) {
chan[i].freq=chan[i].baseFreq+chan[i].pitch-128+chan[i].pitch2;
if (!parent->song.oldArpStrategy) {
if (!parent->song.compatFlags.oldArpStrategy) {
if (chan[i].fixedArp) {
chan[i].freq=(chan[i].baseNoteOverride<<7)+chan[i].pitch-128+chan[i].pitch2;
} else {
@ -862,7 +862,7 @@ int DivPlatformArcade::dispatch(DivCommand c) {
return 127;
break;
case DIV_CMD_PRE_PORTA:
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_LINEAR(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_LINEAR(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_PRE_NOTE:

View file

@ -716,7 +716,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
}
chan[c.chan].active=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
//chan[c.chan].keyOn=true;
@ -735,7 +735,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (!(chan[c.chan].nextPSGMode.val&8)) {
@ -942,9 +942,9 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AY));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AY));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_PRE_NOTE:

View file

@ -544,7 +544,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
}
chan[c.chan].active=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
//chan[c.chan].keyOn=true;
@ -563,7 +563,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (!(chan[c.chan].nextPSGMode.val&8)) {
@ -764,9 +764,9 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AY8930));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AY8930));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_PRE_NOTE:

View file

@ -176,7 +176,7 @@ int DivPlatformBifurcator::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
break;
@ -250,9 +250,9 @@ int DivPlatformBifurcator::dispatch(DivCommand c) {
}
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_BIFURCATOR_STATE_LOAD:

View file

@ -164,7 +164,7 @@ int DivPlatformBubSysWSG::dispatch(DivCommand c) {
chan[c.chan].keyOn=true;
rWrite(2+c.chan,(chan[c.chan].wave<<5)|chan[c.chan].vol);
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (chan[c.chan].wave<0) {
@ -243,9 +243,9 @@ int DivPlatformBubSysWSG::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SCC));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SCC));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -357,7 +357,7 @@ int DivPlatformC140::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
chan[c.chan].volChangedL=true;
chan[c.chan].volChangedR=true;
@ -445,9 +445,9 @@ int DivPlatformC140::dispatch(DivCommand c) {
}
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_SAMPLE_POS:

View file

@ -574,12 +574,12 @@ int DivPlatformC64::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta || parent->song.preNoteNoEffect) {
if (parent->song.compatFlags.resetMacroOnPorta || parent->song.compatFlags.preNoteNoEffect) {
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_C64));
chan[c.chan].keyOn=true;
}
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_PRE_NOTE:

View file

@ -358,7 +358,7 @@ int DivPlatformDave::dispatch(DivCommand c) {
chan[c.chan].keyOn=true;
chan[c.chan].writeVol=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
chan[c.chan].insChanged=false;
@ -471,9 +471,9 @@ int DivPlatformDave::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_DAVE));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_DAVE));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_SAMPLE_POS:

View file

@ -23,7 +23,7 @@
#include <math.h>
#define PITCH_OFFSET ((double)(16*2048*(chanMax+1)))
#define NOTE_ES5506(c,note) ((amigaPitch && !parent->song.linearPitch)?parent->calcBaseFreq(COLOR_NTSC*16,chan[c].pcm.freqOffs,note,true):parent->calcBaseFreq(chipClock,chan[c].pcm.freqOffs,note,false))
#define NOTE_ES5506(c,note) ((amigaPitch && !parent->song.compatFlags.linearPitch)?parent->calcBaseFreq(COLOR_NTSC*16,chan[c].pcm.freqOffs,note,true):parent->calcBaseFreq(chipClock,chan[c].pcm.freqOffs,note,false))
#define rWrite(a,...) {if(!skipRegisterWrites) {hostIntf32.push_back(QueuedHostIntf(4,(a),__VA_ARGS__)); }}
#define immWrite(a,...) {hostIntf32.push_back(QueuedHostIntf(4,(a),__VA_ARGS__));}
@ -603,7 +603,7 @@ void DivPlatformES5506::tick(bool sysTick) {
const unsigned int length=s->samples-1;
const unsigned int end=start+(length<<11);
const unsigned int nextBank=(offES5506>>22)&3;
const double nextFreqOffs=((amigaPitch && !parent->song.linearPitch)?16:PITCH_OFFSET)*off;
const double nextFreqOffs=((amigaPitch && !parent->song.compatFlags.linearPitch)?16:PITCH_OFFSET)*off;
chan[i].pcm.loopMode=loopMode;
chan[i].pcm.bank=nextBank;
chan[i].pcm.start=start;
@ -746,7 +746,7 @@ void DivPlatformES5506::tick(bool sysTick) {
chan[i].pcm.nextPos=0;
}
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
if (amigaPitch && !parent->song.linearPitch) {
if (amigaPitch && !parent->song.compatFlags.linearPitch) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch*16,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,2,chan[i].pitch2*16,16*COLOR_NTSC,chan[i].pcm.freqOffs);
chan[i].freq=PITCH_OFFSET*(COLOR_NTSC/chan[i].freq)/(chipClock/16.0);
chan[i].freq=CLAMP(chan[i].freq,0,0x1ffff);
@ -767,7 +767,7 @@ void DivPlatformES5506::tick(bool sysTick) {
}
chan[i].pcm.loopStart=(chan[i].pcm.start+(s->loopStart<<11))&0xfffff800;
chan[i].pcm.loopEnd=(chan[i].pcm.start+((s->loopEnd)<<11))&0xffffff80;
chan[i].pcm.freqOffs=((amigaPitch && !parent->song.linearPitch)?16:PITCH_OFFSET)*off;
chan[i].pcm.freqOffs=((amigaPitch && !parent->song.compatFlags.linearPitch)?16:PITCH_OFFSET)*off;
unsigned int startPos=chan[i].pcm.direction?chan[i].pcm.end:chan[i].pcm.start;
if (chan[i].pcm.nextPos) {
const unsigned int start=chan[i].pcm.start;
@ -1212,7 +1212,7 @@ int DivPlatformES5506::dispatch(DivCommand c) {
int nextFreq=chan[c.chan].baseFreq;
int destFreq=NOTE_ES5506(c.chan,c.value2+chan[c.chan].sampleNoteDelta);
bool return2=false;
if (amigaPitch && !parent->song.linearPitch) {
if (amigaPitch && !parent->song.compatFlags.linearPitch) {
c.value*=16;
}
if (destFreq>nextFreq) {
@ -1244,9 +1244,9 @@ int DivPlatformES5506::dispatch(DivCommand c) {
}
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_ES5506));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_ES5506));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) {
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) {
chan[c.chan].nextNote=chan[c.chan].note;
chan[c.chan].noteChanged.note=1;
}

View file

@ -337,7 +337,7 @@ void DivPlatformESFM::tick(bool sysTick) {
if (chan[i].freqChanged) {
int mul=2;
int fixedBlock=chan[i].state.fm.block;
if (!parent->song.linearPitch) {
if (!parent->song.compatFlags.linearPitch) {
mul=octave(chan[i].baseFreq,fixedBlock)*2;
}
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,mul,chan[i].pitch2,chipClock,CHIP_FREQBASE);
@ -569,7 +569,7 @@ int DivPlatformESFM::dispatch(DivCommand c) {
bool return2=false;
int mul=1;
int fixedBlock=0;
if (!parent->song.linearPitch) {
if (!parent->song.compatFlags.linearPitch) {
fixedBlock=chan[c.chan].state.fm.block;
mul=octave(chan[c.chan].baseFreq,fixedBlock);
}
@ -586,7 +586,7 @@ int DivPlatformESFM::dispatch(DivCommand c) {
return2=true;
}
}
if (!chan[c.chan].portaPause && !parent->song.linearPitch) {
if (!chan[c.chan].portaPause && !parent->song.compatFlags.linearPitch) {
if (mul!=octave(newFreq,fixedBlock)) {
chan[c.chan].portaPause=true;
break;
@ -987,7 +987,7 @@ int DivPlatformESFM::dispatch(DivCommand c) {
return 63;
break;
case DIV_CMD_PRE_PORTA:
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) {
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) {
chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
}
chan[c.chan].inPorta=c.value;

View file

@ -132,7 +132,7 @@ void DivPlatformFDS::tick(bool sysTick) {
if (chan[i].std.duty.had) {
chan[i].duty=chan[i].std.duty.val;
if (i==3) {
if (parent->song.properNoiseLayout) {
if (parent->song.compatFlags.properNoiseLayout) {
chan[i].duty&=1;
} else if (chan[i].duty>1) {
chan[i].duty=1;
@ -264,7 +264,7 @@ int DivPlatformFDS::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (chan[c.chan].wave<0) {
@ -390,9 +390,9 @@ int DivPlatformFDS::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FDS));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FDS));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -31,7 +31,7 @@
int newFreq; \
bool return2=false; \
if (_targetChan.portaPause) { \
if (parent->song.oldOctaveBoundary) { \
if (parent->song.compatFlags.oldOctaveBoundary) { \
if ((_targetChan.portaPauseFreq&0xf800)>(_targetChan.baseFreq&0xf800)) { \
_targetChan.baseFreq=((_targetChan.baseFreq&0x7ff)>>1)|(_targetChan.portaPauseFreq&0xf800); \
} else { \
@ -59,7 +59,7 @@
/* what the heck! */ \
if (!_targetChan.portaPause) { \
if ((newFreq&0x7ff)>boundaryTop && (newFreq&0xf800)<0x3800) { \
if (parent->song.fbPortaPause) { \
if (parent->song.compatFlags.fbPortaPause) { \
_targetChan.portaPauseFreq=(boundaryBottom)|((newFreq+0x800)&0xf800); \
_targetChan.portaPause=true; \
break; \
@ -68,7 +68,7 @@
} \
} \
if ((newFreq&0x7ff)<boundaryBottom && (newFreq&0xf800)>0) { \
if (parent->song.fbPortaPause) { \
if (parent->song.compatFlags.fbPortaPause) { \
_targetChan.portaPauseFreq=newFreq=(boundaryTop-1)|((newFreq-0x800)&0xf800); \
_targetChan.portaPause=true; \
break; \

View file

@ -261,7 +261,7 @@ int DivPlatformGA20::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
chan[c.chan].volumeChanged=true;
}
@ -332,9 +332,9 @@ int DivPlatformGA20::dispatch(DivCommand c) {
}
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_SAMPLE_POS:

View file

@ -224,7 +224,7 @@ void DivPlatformGB::tick(bool sysTick) {
if (i!=2) {
rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(chan[i].soundLen&63)));
} else if (!chan[i].softEnv) {
if (parent->song.waveDutyIsVol) {
if (parent->song.compatFlags.waveDutyIsVol) {
rWrite(16+i*5+2,(model==GB_MODEL_AGB_NATIVE?gbVolMapEx:gbVolMap)[(chan[i].std.duty.val&3)<<2]);
}
}
@ -439,7 +439,7 @@ int DivPlatformGB::dispatch(DivCommand c) {
chan[c.chan].outVol=chan[c.chan].envVol;
}
} else if (chan[c.chan].softEnv && c.chan!=2) {
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
chan[c.chan].envVol=chan[c.chan].outVol;
}
@ -478,7 +478,7 @@ int DivPlatformGB::dispatch(DivCommand c) {
chan[c.chan].soundLen=ins->gb.soundLen;
chan[c.chan].vol=chan[c.chan].envVol;
chan[c.chan].outVol=chan[c.chan].vol;
if (parent->song.gbInsAffectsEnvelope) {
if (parent->song.compatFlags.gbInsAffectsEnvelope) {
rWrite(16+c.chan*5+2,((chan[c.chan].vol<<4))|(chan[c.chan].envLen&7)|((chan[c.chan].envDir&1)<<3));
}
}
@ -567,9 +567,9 @@ int DivPlatformGB::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_GB));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_GB));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GB_SWEEP_DIR:

View file

@ -237,7 +237,7 @@ int DivPlatformGBADMA::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].envVol=2;
}
if (chan[c.chan].useWave) {
@ -321,7 +321,7 @@ int DivPlatformGBADMA::dispatch(DivCommand c) {
}
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
}
chan[c.chan].inPorta=c.value;
break;

View file

@ -417,7 +417,7 @@ int DivPlatformGBAMinMod::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
break;
@ -503,9 +503,9 @@ int DivPlatformGBAMinMod::dispatch(DivCommand c) {
}
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_SAMPLE_POS:

View file

@ -68,7 +68,7 @@ void DivPlatformGenesis::processDAC(int iRate) {
if (chan[i].dacSample!=-1) {
DivSample* s=parent->getSample(chan[i].dacSample);
if (!isMuted[i] && s->samples>0 && chan[i].dacPos<s->samples) {
if (parent->song.noOPN2Vol) {
if (parent->song.compatFlags.noOPN2Vol) {
chan[i].dacOutput=s->data8[chan[i].dacDirection?(s->samples-chan[i].dacPos-1):chan[i].dacPos];
} else {
chan[i].dacOutput=(s->data8[chan[i].dacDirection?(s->samples-chan[i].dacPos-1):chan[i].dacPos]*dacVolTable[chan[i].outVol])>>7;
@ -110,7 +110,7 @@ void DivPlatformGenesis::processDAC(int iRate) {
if (s->samples>0 && chan[5].dacPos<s->samples) {
if (!isMuted[5]) {
int sample;
if (parent->song.noOPN2Vol) {
if (parent->song.compatFlags.noOPN2Vol) {
sample=s->data8[chan[5].dacDirection?(s->samples-chan[5].dacPos-1):chan[5].dacPos];
} else {
sample=(s->data8[chan[5].dacDirection?(s->samples-chan[5].dacPos-1):chan[5].dacPos]*dacVolTable[chan[5].outVol])>>7;
@ -122,7 +122,7 @@ void DivPlatformGenesis::processDAC(int iRate) {
chan[5].dacPos=s->loopStart;
} else if (chan[5].dacPos>=s->samples) {
chan[5].dacSample=-1;
if (parent->song.brokenDACMode) {
if (parent->song.compatFlags.brokenDACMode) {
rWrite(0x2b,0);
}
}
@ -768,7 +768,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
if (chan[i].std.alg.had) {
chan[i].state.alg=chan[i].std.alg.val;
rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) {
if (!parent->song.compatFlags.algMacroBehavior) for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
if (isMuted[i] || !op.enable) {
@ -863,7 +863,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
for (int i=0; i<512; i++) {
if (pendingWrites[i]!=oldWrites[i]) {
if (i==0x2b && pendingWrites[i]!=0 && !parent->song.brokenDACMode) {
if (i==0x2b && pendingWrites[i]!=0 && !parent->song.compatFlags.brokenDACMode) {
if (chan[5].keyOn) chan[5].keyOn=false;
chan[5].keyOff=true;
}
@ -894,7 +894,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
for (int i=0; i<csmChan; i++) {
if (i==2 && extMode) continue;
if (chan[i].freqChanged) {
if (parent->song.linearPitch) {
if (parent->song.compatFlags.linearPitch) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE,11,chan[i].state.block);
} else {
int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE,11);
@ -1131,7 +1131,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
if (c.chan>=5 && c.chan<csmChan) {
chan[c.chan].dacSample=-1;
if (dumpWrites) addWrite(0xffff0002,0);
if (parent->song.brokenDACMode) {
if (parent->song.compatFlags.brokenDACMode) {
rWrite(0x2b,0);
if (chan[c.chan].dacMode) break;
}
@ -1200,7 +1200,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
break;
}
case DIV_CMD_NOTE_PORTA: {
if (parent->song.linearPitch) {
if (parent->song.compatFlags.linearPitch) {
int destFreq=NOTE_FREQUENCY(c.value2+chan[c.chan].sampleNoteDelta);
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {

View file

@ -153,7 +153,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
} else {
opChan[ch].pan=(c.value2>0)|((c.value>0)<<1);
}
if (parent->song.sharedExtStat) {
if (parent->song.compatFlags.sharedExtStat) {
for (int i=0; i<4; i++) {
if (ch==i) continue;
opChan[i].pan=opChan[ch].pan;
@ -169,7 +169,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
break;
}
case DIV_CMD_NOTE_PORTA: {
if (parent->song.linearPitch) {
if (parent->song.compatFlags.linearPitch) {
int destFreq=NOTE_FREQUENCY(c.value2);
bool return2=false;
if (destFreq>opChan[ch].baseFreq) {
@ -197,7 +197,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
}
case DIV_CMD_SAMPLE_MODE: {
// not ignored actually!
if (!parent->song.ignoreDACModeOutsideIntendedChannel) {
if (!parent->song.compatFlags.ignoreDACModeOutsideIntendedChannel) {
chan[5].dacMode=c.value;
rWrite(0x2b,c.value<<7);
}
@ -547,7 +547,7 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
if (opChan[i].std.alg.had) {
chan[extChanOffs].state.alg=opChan[i].std.alg.val;
rWrite(chanOffs[extChanOffs]+ADDR_FB_ALG,(chan[extChanOffs].state.alg&7)|(chan[extChanOffs].state.fb<<3));
if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) {
if (!parent->song.compatFlags.algMacroBehavior) for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[j];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[j];
if (isOpMuted[j] || !op.enable) {
@ -578,7 +578,7 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
if (opChan[i].std.panL.had) {
opChan[i].pan=opChan[i].std.panL.val&3;
if (parent->song.sharedExtStat) {
if (parent->song.compatFlags.sharedExtStat) {
for (int j=0; j<4; j++) {
if (i==j) continue;
opChan[j].pan=opChan[i].pan;
@ -648,7 +648,7 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
unsigned char hardResetMask=0;
if (extMode) for (int i=0; i<4; i++) {
if (opChan[i].freqChanged) {
if (parent->song.linearPitch) {
if (parent->song.compatFlags.linearPitch) {
opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch,opChan[i].fixedArp?opChan[i].baseNoteOverride:opChan[i].arpOff,opChan[i].fixedArp,false,2,opChan[i].pitch2,chipClock,CHIP_FREQBASE,11,chan[extChanOffs].state.block);
} else {
int fNum=parent->calcFreq(opChan[i].baseFreq&0x7ff,opChan[i].pitch,opChan[i].fixedArp?opChan[i].baseNoteOverride:opChan[i].arpOff,opChan[i].fixedArp,false,2,opChan[i].pitch2);

View file

@ -324,7 +324,7 @@ int DivPlatformK007232::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
if (!isMuted[c.chan]) {
chan[c.chan].volumeChanged=true;
@ -405,9 +405,9 @@ int DivPlatformK007232::dispatch(DivCommand c) {
}
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_SAMPLE_POS:

View file

@ -255,7 +255,7 @@ int DivPlatformK053260::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
break;
@ -331,9 +331,9 @@ int DivPlatformK053260::dispatch(DivCommand c) {
}
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_SAMPLE_POS:

View file

@ -361,7 +361,7 @@ int DivPlatformLynx::dispatch(DivCommand c) {
chan[c.chan].active=true;
WRITE_VOLUME(c.chan,(isMuted[c.chan]?0:(chan[c.chan].vol&127)));
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
break;
@ -429,7 +429,7 @@ int DivPlatformLynx::dispatch(DivCommand c) {
}
}
chan[c.chan].freqChanged=true;
if (chan[c.chan].pcm && parent->song.linearPitch) {
if (chan[c.chan].pcm && parent->song.compatFlags.linearPitch) {
chan[c.chan].sampleBaseFreq=chan[c.chan].baseFreq;
}
if (return2) {
@ -451,9 +451,9 @@ int DivPlatformLynx::dispatch(DivCommand c) {
}
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_SAMPLE_POS:

View file

@ -229,7 +229,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
rWrite(0x5000+c.chan*4,0x30|chan[c.chan].vol|((chan[c.chan].duty&3)<<6));
@ -313,9 +313,9 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -157,7 +157,7 @@ void DivPlatformMSM5232::tick(bool sysTick) {
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
//DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_PCE);
chan[i].freq=chan[i].baseFreq+chan[i].pitch+chan[i].pitch2-(12<<7);
if (!parent->song.oldArpStrategy) {
if (!parent->song.compatFlags.oldArpStrategy) {
if (chan[i].fixedArp) {
chan[i].freq=(chan[i].baseNoteOverride<<7)+(chan[i].pitch)-(12<<7);
} else {
@ -206,7 +206,7 @@ int DivPlatformMSM5232::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
chan[c.chan].insChanged=false;
@ -249,13 +249,13 @@ int DivPlatformMSM5232::dispatch(DivCommand c) {
int destFreq=NOTE_LINEAR(c.value2);
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {
chan[c.chan].baseFreq+=c.value*parent->song.pitchSlideSpeed;
chan[c.chan].baseFreq+=c.value*parent->song.compatFlags.pitchSlideSpeed;
if (chan[c.chan].baseFreq>=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
}
} else {
chan[c.chan].baseFreq-=c.value*parent->song.pitchSlideSpeed;
chan[c.chan].baseFreq-=c.value*parent->song.compatFlags.pitchSlideSpeed;
if (chan[c.chan].baseFreq<=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
@ -291,9 +291,9 @@ int DivPlatformMSM5232::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_PCE));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_PCE));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_LINEAR(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_LINEAR(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -101,7 +101,7 @@ void DivPlatformMSM6258::acquire(short** buf, size_t len) {
void DivPlatformMSM6258::tick(bool sysTick) {
for (int i=0; i<1; i++) {
if (!parent->song.disableSampleMacro) {
if (!parent->song.compatFlags.disableSampleMacro) {
chan[i].std.next();
if (chan[i].std.duty.had) {
if (rateSel!=(chan[i].std.duty.val&3)) {

View file

@ -122,7 +122,7 @@ void DivPlatformMSM6295::acquire(short** buf, size_t len) {
void DivPlatformMSM6295::tick(bool sysTick) {
for (int i=0; i<4; i++) {
if (!parent->song.disableSampleMacro) {
if (!parent->song.compatFlags.disableSampleMacro) {
chan[i].std.next();
if (chan[i].std.vol.had) {
chan[i].outVol=VOL_SCALE_LOG_BROKEN(chan[i].std.vol.val,chan[i].vol,8);

View file

@ -389,9 +389,9 @@ int DivPlatformMultiPCM::dispatch(DivCommand c) {
return 127;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_MULTIPCM));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_MULTIPCM));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) {
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) {
chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
}
chan[c.chan].inPorta=c.value;

View file

@ -386,13 +386,13 @@ int DivPlatformN163::dispatch(DivCommand c) {
int destFreq=destFreqD;
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {
chan[c.chan].baseFreq+=c.value*((parent->song.linearPitch)?1:16);
chan[c.chan].baseFreq+=c.value*((parent->song.compatFlags.linearPitch)?1:16);
if (chan[c.chan].baseFreq>=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
}
} else {
chan[c.chan].baseFreq-=c.value*((parent->song.linearPitch)?1:16);
chan[c.chan].baseFreq-=c.value*((parent->song.compatFlags.linearPitch)?1:16);
if (chan[c.chan].baseFreq<=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
@ -456,12 +456,12 @@ int DivPlatformN163::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) {
if (parent->song.compatFlags.resetMacroOnPorta) {
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_N163));
chan[c.chan].keyOn=true;
}
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:
@ -593,7 +593,7 @@ void DivPlatformN163::setFlags(const DivConfig& flags) {
break;
}
CHECK_CUSTOM_CLOCK;
initChanMax=chanMax=flags.getInt("channels",0)&7;
initChanMax=chanMax=flags.getInt("channels",7)&7;
multiplex=!flags.getBool("multiplex",false); // not accurate in real hardware
rate=chipClock;
rate/=15;
@ -602,6 +602,7 @@ void DivPlatformN163::setFlags(const DivConfig& flags) {
for (int i=0; i<8; i++) {
oscBuf[i]->setRate(rate);//=rate/(initChanMax+1);
}
logV("N163: initChanMax: %d",initChanMax);
lenCompensate=flags.getBool("lenCompensate",false);
@ -618,6 +619,8 @@ int DivPlatformN163::init(DivEngine* p, int channels, int sugRate, const DivConf
oscBuf[i]=new DivDispatchOscBuffer;
}
logV("N163: init(%d)",channels);
memCompo.used=0;
memCompo.capacity=128;
memCompo.memory=regPool;

View file

@ -353,7 +353,7 @@ int DivPlatformNamcoWSG::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (chan[c.chan].wave<0) {
@ -406,13 +406,13 @@ int DivPlatformNamcoWSG::dispatch(DivCommand c) {
int destFreq=NOTE_FREQUENCY(c.value2);
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {
chan[c.chan].baseFreq+=c.value*((parent->song.linearPitch)?1:8);
chan[c.chan].baseFreq+=c.value*((parent->song.compatFlags.linearPitch)?1:8);
if (chan[c.chan].baseFreq>=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
}
} else {
chan[c.chan].baseFreq-=c.value*((parent->song.linearPitch)?1:8);
chan[c.chan].baseFreq-=c.value*((parent->song.compatFlags.linearPitch)?1:8);
if (chan[c.chan].baseFreq<=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
@ -440,9 +440,9 @@ int DivPlatformNamcoWSG::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_PCE));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_PCE));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -334,7 +334,7 @@ int DivPlatformNDS::dispatch(DivCommand c) {
chan[c.chan].busy=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
break;
@ -422,9 +422,9 @@ int DivPlatformNDS::dispatch(DivCommand c) {
}
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_NDS));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_NDS));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_SAMPLE_POS:

View file

@ -326,7 +326,7 @@ void DivPlatformNES::tick(bool sysTick) {
if (chan[i].std.duty.had) {
chan[i].duty=chan[i].std.duty.val;
if (i==3) {
if (parent->song.properNoiseLayout) {
if (parent->song.compatFlags.properNoiseLayout) {
chan[i].duty&=1;
} else if (chan[i].duty>1) {
chan[i].duty=1;
@ -372,7 +372,7 @@ void DivPlatformNES::tick(bool sysTick) {
ntPos+=chan[i].pitch2;
if (isE) {
chan[i].freq=31-(ntPos&31);
} else if (parent->song.properNoiseLayout) {
} else if (parent->song.compatFlags.properNoiseLayout) {
chan[i].freq=15-(ntPos&15);
} else {
if (ntPos<0) ntPos=0;
@ -578,12 +578,12 @@ int DivPlatformNES::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_NES));
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (c.chan==2) {
rWrite(0x4000+c.chan*4,linearCount);
} else if (!parent->song.brokenOutVol2) {
} else if (!parent->song.compatFlags.brokenOutVol2) {
rWrite(0x4000+c.chan*4,(chan[c.chan].envMode<<4)|chan[c.chan].vol|((chan[c.chan].duty&3)<<6));
}
if (resetSweep && c.chan<2) {
@ -752,9 +752,9 @@ int DivPlatformNES::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_NES));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_NES));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -1515,7 +1515,7 @@ void DivPlatformOPL::tick(bool sysTick) {
if (chan[i].freqChanged) {
int mul=2;
int fixedBlock=chan[i].state.block;
if (!parent->song.linearPitch) {
if (!parent->song.compatFlags.linearPitch) {
mul=octave(chan[i].baseFreq,fixedBlock)*2;
}
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,mul,chan[i].pitch2,chipClock,CHIP_FREQBASE);
@ -2082,7 +2082,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
bool return2=false;
int mul=1;
int fixedBlock=0;
if (!parent->song.linearPitch) {
if (!parent->song.compatFlags.linearPitch) {
fixedBlock=chan[c.chan].state.block;
mul=octave(chan[c.chan].baseFreq,fixedBlock);
}
@ -2099,7 +2099,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
return2=true;
}
}
if (!chan[c.chan].portaPause && !parent->song.linearPitch) {
if (!chan[c.chan].portaPause && !parent->song.compatFlags.linearPitch) {
if (mul!=octave(newFreq,fixedBlock)) {
chan[c.chan].portaPause=true;
break;
@ -2583,9 +2583,9 @@ int DivPlatformOPL::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (PCM_CHECK(c.chan) && chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_MULTIPCM));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_MULTIPCM));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) {
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) {
chan[c.chan].baseFreq=(PCM_CHECK(c.chan))?NOTE_PCM(chan[c.chan].note):
((c.chan==adpcmChan)?(NOTE_ADPCMB(chan[c.chan].note)):(NOTE_FREQUENCY(chan[c.chan].note)));
}

View file

@ -341,7 +341,7 @@ void DivPlatformOPLL::tick(bool sysTick) {
if (chan[i].freqChanged) {
int mul=2;
int fixedBlock=chan[i].state.block;
if (!parent->song.linearPitch) {
if (!parent->song.compatFlags.linearPitch) {
mul=octave(chan[i].baseFreq,fixedBlock)*2;
}
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,mul,chan[i].pitch2,chipClock,CHIP_FREQBASE);
@ -684,7 +684,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
bool return2=false;
int mul=1;
int fixedBlock=0;
if (!parent->song.linearPitch) {
if (!parent->song.compatFlags.linearPitch) {
fixedBlock=chan[c.chan].state.block;
mul=octave(chan[c.chan].baseFreq,fixedBlock);
}
@ -956,7 +956,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (c.chan>=9 && !properDrums) return 0;
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_PRE_NOTE:

View file

@ -103,7 +103,7 @@ void DivPlatformPCE::acquireDirect(blip_buffer_t** bb, size_t len) {
signed char dacData=((signed char)((unsigned char)s->data8[chan[i].dacPos]^0x80))>>3;
chan[i].dacOut=CLAMP(dacData,-16,15);
if (!isMuted[i]) {
chWrite(i,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[i].outVol));
chWrite(i,0x04,parent->song.compatFlags.disableSampleMacro?0xdf:(0xc0|chan[i].outVol));
chWrite(i,0x06,chan[i].dacOut&0x1f);
} else {
chWrite(i,0x04,0xc0);
@ -233,7 +233,7 @@ void DivPlatformPCE::tick(bool sysTick) {
chan[i].dacPos=0;
}
chan[i].dacPeriod=0;
chWrite(i,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[i].vol));
chWrite(i,0x04,parent->song.compatFlags.disableSampleMacro?0xdf:(0xc0|chan[i].vol));
addWrite(0xffff0000+(i<<8),chan[i].dacSample);
chan[i].keyOn=true;
}
@ -269,11 +269,11 @@ void DivPlatformPCE::tick(bool sysTick) {
if (i>=4) {
int noiseSeek=(chan[i].fixedArp?chan[i].baseNoteOverride:(chan[i].note+chan[i].arpOff))+chan[i].pitch2;
if (!parent->song.properNoiseLayout && noiseSeek<0) noiseSeek=0;
if (!parent->song.compatFlags.properNoiseLayout && noiseSeek<0) noiseSeek=0;
if (!NEW_ARP_STRAT) {
noiseSeek=chan[i].noiseSeek;
}
chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0);
chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.compatFlags.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0);
}
if (chan[i].keyOn) {
//rWrite(16+i*5,0x80);
@ -324,7 +324,7 @@ int DivPlatformPCE::dispatch(DivCommand c) {
break;
} else {
if (dumpWrites) {
chWrite(c.chan,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[c.chan].vol));
chWrite(c.chan,0x04,parent->song.compatFlags.disableSampleMacro?0xdf:(0xc0|chan[c.chan].vol));
addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dacSample);
}
}
@ -341,7 +341,7 @@ int DivPlatformPCE::dispatch(DivCommand c) {
}
chan[c.chan].active=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
break;
@ -359,7 +359,7 @@ int DivPlatformPCE::dispatch(DivCommand c) {
chan[c.chan].keyOn=true;
chWrite(c.chan,0x04,0x80|chan[c.chan].vol);
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (chan[c.chan].wave<0) {
@ -476,9 +476,9 @@ int DivPlatformPCE::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_PCE));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_PCE));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:
@ -503,7 +503,7 @@ void DivPlatformPCE::muteChannel(int ch, bool mute) {
isMuted[ch]=mute;
chWrite(ch,0x05,isMuted[ch]?0:chan[ch].pan);
if (!isMuted[ch] && (chan[ch].pcm && chan[ch].dacSample!=-1)) {
chWrite(ch,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[ch].outVol));
chWrite(ch,0x04,parent->song.compatFlags.disableSampleMacro?0xdf:(0xc0|chan[ch].outVol));
chWrite(ch,0x06,chan[ch].dacOut&0x1f);
}
}

View file

@ -29,310 +29,342 @@
void DivPlatformPCMDAC::acquire(short** buf, size_t len) {
const int depthScale=(15-outDepth);
int output=0;
int outSum[2];
oscBuf->begin(len);
for (size_t h=0; h<len; h++) {
if (!chan[0].active) {
// do not process if our channels are null
if (chan==NULL) {
for (size_t h=0; h<len; h++) {
buf[0][h]=0;
buf[1][h]=0;
oscBuf->putSample(h,0);
continue;
}
if (chan[0].useWave || (chan[0].sample>=0 && chan[0].sample<parent->song.sampleLen)) {
chan[0].audSub+=chan[0].freq;
if (chan[0].useWave) {
while (chan[0].audSub>=0x10000) {
chan[0].audSub-=0x10000;
chan[0].audPos+=((!chan[0].useWave) && chan[0].audDir)?-1:1;
if (chan[0].audPos>=(int)chan[0].audLen) {
chan[0].audPos%=chan[0].audLen;
chan[0].audDir=false;
}
chan[0].audDat[0]=chan[0].audDat[1];
chan[0].audDat[1]=chan[0].audDat[2];
chan[0].audDat[2]=chan[0].audDat[3];
chan[0].audDat[3]=chan[0].audDat[4];
chan[0].audDat[4]=chan[0].audDat[5];
chan[0].audDat[5]=chan[0].audDat[6];
chan[0].audDat[6]=chan[0].audDat[7];
chan[0].audDat[7]=(chan[0].ws.output[chan[0].audPos]-0x80)<<8;
}
const short s0=chan[0].audDat[0];
const short s1=chan[0].audDat[1];
const short s2=chan[0].audDat[2];
const short s3=chan[0].audDat[3];
const short s4=chan[0].audDat[4];
const short s5=chan[0].audDat[5];
const short s6=chan[0].audDat[6];
const short s7=chan[0].audDat[7];
switch (interp) {
case 1: // linear
output=s6+(((int)((int)s7-(int)s6)*((chan[0].audSub>>1)&0x7fff))>>15);
break;
case 2: { // cubic
float* cubicTable=DivFilterTables::getCubicTable();
float* t=&cubicTable[((chan[0].audSub&0xffff)>>6)<<2];
float result=(float)s4*t[0]+(float)s5*t[1]+(float)s6*t[2]+(float)s7*t[3];
if (result<-32768) result=-32768;
if (result>32767) result=32767;
output=result;
break;
}
case 3: { // sinc
float* sincTable=DivFilterTables::getSincTable8();
float* t1=&sincTable[(8191-((chan[0].audSub&0xffff)>>3))<<2];
float* t2=&sincTable[((chan[0].audSub&0xffff)>>3)<<2];
float result=(
s0*t2[3]+
s1*t2[2]+
s2*t2[1]+
s3*t2[0]+
s4*t1[0]+
s5*t1[1]+
s6*t1[2]+
s7*t1[3]
);
if (result<-32768) result=-32768;
if (result>32767) result=32767;
output=result;
break;
}
default: // none
output=s7;
break;
}
} else {
DivSample* s=parent->getSample(chan[0].sample);
if (s->samples>0) {
while (chan[0].audSub>=0x10000) {
chan[0].audSub-=0x10000;
chan[0].audPos+=((!chan[0].useWave) && chan[0].audDir)?-1:1;
if (chan[0].audDir) {
if (s->isLoopable()) {
switch (s->loopMode) {
case DIV_SAMPLE_LOOP_FORWARD:
case DIV_SAMPLE_LOOP_PINGPONG:
if (chan[0].audPos<s->loopStart) {
chan[0].audPos=s->loopStart+(s->loopStart-chan[0].audPos);
chan[0].audDir=false;
}
break;
case DIV_SAMPLE_LOOP_BACKWARD:
if (chan[0].audPos<s->loopStart) {
chan[0].audPos=s->loopEnd-1-(s->loopStart-chan[0].audPos);
chan[0].audDir=true;
}
break;
default:
if (chan[0].audPos<0) {
chan[0].sample=-1;
}
break;
}
} else if (chan[0].audPos>=(int)s->samples) {
chan[0].sample=-1;
}
} else {
if (s->isLoopable()) {
switch (s->loopMode) {
case DIV_SAMPLE_LOOP_FORWARD:
if (chan[0].audPos>=s->loopEnd) {
chan[0].audPos=(chan[0].audPos+s->loopStart)-s->loopEnd;
chan[0].audDir=false;
}
break;
case DIV_SAMPLE_LOOP_BACKWARD:
case DIV_SAMPLE_LOOP_PINGPONG:
if (chan[0].audPos>=s->loopEnd) {
chan[0].audPos=s->loopEnd-1-(s->loopEnd-1-chan[0].audPos);
chan[0].audDir=true;
}
break;
default:
if (chan[0].audPos>=(int)s->samples) {
chan[0].sample=-1;
}
break;
}
} else if (chan[0].audPos>=(int)s->samples) {
chan[0].sample=-1;
}
}
chan[0].audDat[0]=chan[0].audDat[1];
chan[0].audDat[1]=chan[0].audDat[2];
chan[0].audDat[2]=chan[0].audDat[3];
chan[0].audDat[3]=chan[0].audDat[4];
chan[0].audDat[4]=chan[0].audDat[5];
chan[0].audDat[5]=chan[0].audDat[6];
chan[0].audDat[6]=chan[0].audDat[7];
if (chan[0].audPos>=0 && chan[0].audPos<(int)s->samples) {
chan[0].audDat[7]=s->data16[chan[0].audPos];
} else {
chan[0].audDat[7]=0;
}
}
} else {
chan[0].sample=-1;
chan[0].audSub=0;
chan[0].audPos=0;
}
const short s0=chan[0].audDat[0];
const short s1=chan[0].audDat[1];
const short s2=chan[0].audDat[2];
const short s3=chan[0].audDat[3];
const short s4=chan[0].audDat[4];
const short s5=chan[0].audDat[5];
const short s6=chan[0].audDat[6];
const short s7=chan[0].audDat[7];
switch (interp) {
case 1: // linear
output=s6+(((int)((int)s7-(int)s6)*((chan[0].audSub>>1)&0x7fff))>>15);
break;
case 2: { // cubic
float* cubicTable=DivFilterTables::getCubicTable();
float* t=&cubicTable[((chan[0].audSub&0xffff)>>6)<<2];
float result=(float)s4*t[0]+(float)s5*t[1]+(float)s6*t[2]+(float)s7*t[3];
if (result<-32768) result=-32768;
if (result>32767) result=32767;
output=result;
break;
}
case 3: { // sinc
float* sincTable=DivFilterTables::getSincTable8();
float* t1=&sincTable[(8191-((chan[0].audSub&0xffff)>>3))<<2];
float* t2=&sincTable[((chan[0].audSub&0xffff)>>3)<<2];
float result=(
s0*t2[3]+
s1*t2[2]+
s2*t2[1]+
s3*t2[0]+
s4*t1[0]+
s5*t1[1]+
s6*t1[2]+
s7*t1[3]
);
if (result<-32768) result=-32768;
if (result>32767) result=32767;
output=result;
break;
}
default: // none
output=s7;
break;
}
}
}
if (isMuted) {
output=0;
} else {
output=((output*MIN(volMax,chan[0].vol)*MIN(chan[0].envVol,64))>>6)/volMax;
}
oscBuf->putSample(h,((output>>depthScale)<<depthScale)>>1);
if (outStereo) {
buf[0][h]=((output*chan[0].panL)>>(depthScale+8))<<depthScale;
buf[1][h]=((output*chan[0].panR)>>(depthScale+8))<<depthScale;
} else {
output=(output>>depthScale)<<depthScale;
buf[0][h]=output;
buf[1][h]=output;
}
return;
}
oscBuf->end(len);
for (int i=0; i<chans; i++) {
oscBuf[i].begin(len);
}
for (size_t h=0; h<len; h++) {
outSum[0]=0;
outSum[1]=0;
for (int i=0; i<chans; i++) {
output=0;
if (!chan[i].active) {
oscBuf[i].putSample(h,0);
continue;
}
if (chan[i].useWave || (chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen)) {
chan[i].audSub+=chan[i].freq;
if (chan[i].useWave) {
while (chan[i].audSub>=0x10000) {
chan[i].audSub-=0x10000;
chan[i].audPos+=((!chan[i].useWave) && chan[i].audDir)?-1:1;
if (chan[i].audPos>=(int)chan[i].audLen) {
chan[i].audPos%=chan[i].audLen;
chan[i].audDir=false;
}
chan[i].audDat[0]=chan[i].audDat[1];
chan[i].audDat[1]=chan[i].audDat[2];
chan[i].audDat[2]=chan[i].audDat[3];
chan[i].audDat[3]=chan[i].audDat[4];
chan[i].audDat[4]=chan[i].audDat[5];
chan[i].audDat[5]=chan[i].audDat[6];
chan[i].audDat[6]=chan[i].audDat[7];
chan[i].audDat[7]=(chan[i].ws.output[chan[i].audPos]-0x80)<<8;
}
const short s0=chan[i].audDat[0];
const short s1=chan[i].audDat[1];
const short s2=chan[i].audDat[2];
const short s3=chan[i].audDat[3];
const short s4=chan[i].audDat[4];
const short s5=chan[i].audDat[5];
const short s6=chan[i].audDat[6];
const short s7=chan[i].audDat[7];
switch (interp) {
case 1: // linear
output=s6+(((int)((int)s7-(int)s6)*((chan[i].audSub>>1)&0x7fff))>>15);
break;
case 2: { // cubic
float* cubicTable=DivFilterTables::getCubicTable();
float* t=&cubicTable[((chan[i].audSub&0xffff)>>6)<<2];
float result=(float)s4*t[0]+(float)s5*t[1]+(float)s6*t[2]+(float)s7*t[3];
if (result<-32768) result=-32768;
if (result>32767) result=32767;
output=result;
break;
}
case 3: { // sinc
float* sincTable=DivFilterTables::getSincTable8();
float* t1=&sincTable[(8191-((chan[i].audSub&0xffff)>>3))<<2];
float* t2=&sincTable[((chan[i].audSub&0xffff)>>3)<<2];
float result=(
s0*t2[3]+
s1*t2[2]+
s2*t2[1]+
s3*t2[0]+
s4*t1[0]+
s5*t1[1]+
s6*t1[2]+
s7*t1[3]
);
if (result<-32768) result=-32768;
if (result>32767) result=32767;
output=result;
break;
}
default: // none
output=s7;
break;
}
} else {
DivSample* s=parent->getSample(chan[i].sample);
if (s->samples>0) {
while (chan[i].audSub>=0x10000) {
chan[i].audSub-=0x10000;
chan[i].audPos+=((!chan[i].useWave) && chan[i].audDir)?-1:1;
if (chan[i].audDir) {
if (s->isLoopable()) {
switch (s->loopMode) {
case DIV_SAMPLE_LOOP_FORWARD:
case DIV_SAMPLE_LOOP_PINGPONG:
if (chan[i].audPos<s->loopStart) {
chan[i].audPos=s->loopStart+(s->loopStart-chan[i].audPos);
chan[i].audDir=false;
}
break;
case DIV_SAMPLE_LOOP_BACKWARD:
if (chan[i].audPos<s->loopStart) {
chan[i].audPos=s->loopEnd-1-(s->loopStart-chan[i].audPos);
chan[i].audDir=true;
}
break;
default:
if (chan[i].audPos<0) {
chan[i].sample=-1;
}
break;
}
} else if (chan[i].audPos>=(int)s->samples) {
chan[i].sample=-1;
}
} else {
if (s->isLoopable()) {
switch (s->loopMode) {
case DIV_SAMPLE_LOOP_FORWARD:
if (chan[i].audPos>=s->loopEnd) {
chan[i].audPos=(chan[i].audPos+s->loopStart)-s->loopEnd;
chan[i].audDir=false;
}
break;
case DIV_SAMPLE_LOOP_BACKWARD:
case DIV_SAMPLE_LOOP_PINGPONG:
if (chan[i].audPos>=s->loopEnd) {
chan[i].audPos=s->loopEnd-1-(s->loopEnd-1-chan[i].audPos);
chan[i].audDir=true;
}
break;
default:
if (chan[i].audPos>=(int)s->samples) {
chan[i].sample=-1;
}
break;
}
} else if (chan[i].audPos>=(int)s->samples) {
chan[i].sample=-1;
}
}
chan[i].audDat[0]=chan[i].audDat[1];
chan[i].audDat[1]=chan[i].audDat[2];
chan[i].audDat[2]=chan[i].audDat[3];
chan[i].audDat[3]=chan[i].audDat[4];
chan[i].audDat[4]=chan[i].audDat[5];
chan[i].audDat[5]=chan[i].audDat[6];
chan[i].audDat[6]=chan[i].audDat[7];
if (chan[i].audPos>=0 && chan[i].audPos<(int)s->samples) {
chan[i].audDat[7]=s->data16[chan[i].audPos];
} else {
chan[i].audDat[7]=0;
}
}
} else {
chan[i].sample=-1;
chan[i].audSub=0;
chan[i].audPos=0;
}
const short s0=chan[i].audDat[0];
const short s1=chan[i].audDat[1];
const short s2=chan[i].audDat[2];
const short s3=chan[i].audDat[3];
const short s4=chan[i].audDat[4];
const short s5=chan[i].audDat[5];
const short s6=chan[i].audDat[6];
const short s7=chan[i].audDat[7];
switch (interp) {
case 1: // linear
output=s6+(((int)((int)s7-(int)s6)*((chan[i].audSub>>1)&0x7fff))>>15);
break;
case 2: { // cubic
float* cubicTable=DivFilterTables::getCubicTable();
float* t=&cubicTable[((chan[i].audSub&0xffff)>>6)<<2];
float result=(float)s4*t[0]+(float)s5*t[1]+(float)s6*t[2]+(float)s7*t[3];
if (result<-32768) result=-32768;
if (result>32767) result=32767;
output=result;
break;
}
case 3: { // sinc
float* sincTable=DivFilterTables::getSincTable8();
float* t1=&sincTable[(8191-((chan[i].audSub&0xffff)>>3))<<2];
float* t2=&sincTable[((chan[i].audSub&0xffff)>>3)<<2];
float result=(
s0*t2[3]+
s1*t2[2]+
s2*t2[1]+
s3*t2[0]+
s4*t1[0]+
s5*t1[1]+
s6*t1[2]+
s7*t1[3]
);
if (result<-32768) result=-32768;
if (result>32767) result=32767;
output=result;
break;
}
default: // none
output=s7;
break;
}
}
}
if (isMuted[i]) {
output=0;
} else {
output=((output*MIN(volMax,chan[i].vol)*MIN(chan[i].envVol,64))>>6)/volMax;
}
oscBuf[i].putSample(h,((output>>depthScale)<<depthScale)>>1);
if (outStereo) {
outSum[0]+=((output*chan[i].panL)>>(depthScale+8))<<depthScale;
outSum[1]+=((output*chan[i].panR)>>(depthScale+8))<<depthScale;
} else {
output=(output>>depthScale)<<depthScale;
outSum[0]+=output;
outSum[1]+=output;
}
}
outSum[0]=(int)((float)outSum[0]*volMult);
outSum[1]=(int)((float)outSum[1]*volMult);
if (outSum[0]<-32768) outSum[0]=-32768;
if (outSum[0]>32767) outSum[0]=32767;
if (outSum[1]<-32768) outSum[1]=-32768;
if (outSum[1]>32767) outSum[1]=32767;
buf[0][h]=outSum[0];
buf[1][h]=outSum[1];
}
for (int i=0; i<chans; i++) {
oscBuf[i].end(len);
}
}
void DivPlatformPCMDAC::tick(bool sysTick) {
chan[0].std.next();
if (chan[0].std.vol.had) {
chan[0].envVol=chan[0].std.vol.val;
}
if (NEW_ARP_STRAT) {
chan[0].handleArp();
} else if (chan[0].std.arp.had) {
if (!chan[0].inPorta) {
chan[0].baseFreq=NOTE_FREQUENCY(parent->calcArp(chan[0].note,chan[0].std.arp.val));
for (int i=0; i<chans; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
chan[i].envVol=chan[i].std.vol.val;
}
chan[0].freqChanged=true;
}
if (chan[0].useWave && chan[0].std.wave.had) {
if (chan[0].wave!=chan[0].std.wave.val || chan[0].ws.activeChanged()) {
chan[0].wave=chan[0].std.wave.val;
chan[0].ws.changeWave1(chan[0].wave);
if (!chan[0].keyOff) chan[0].keyOn=true;
}
}
if (chan[0].useWave && chan[0].active) {
chan[0].ws.tick();
}
if (chan[0].std.pitch.had) {
if (chan[0].std.pitch.mode) {
chan[0].pitch2+=chan[0].std.pitch.val;
CLAMP_VAR(chan[0].pitch2,-32768,32767);
} else {
chan[0].pitch2=chan[0].std.pitch.val;
}
chan[0].freqChanged=true;
}
if (chan[0].std.panL.had) {
int val=chan[0].std.panL.val&0x7f;
chan[0].panL=val*2;
}
if (chan[0].std.panR.had) {
int val=chan[0].std.panR.val&0x7f;
chan[0].panR=val*2;
}
if (chan[0].std.phaseReset.had) {
if (chan[0].std.phaseReset.val==1) {
chan[0].audDir=false;
chan[0].audPos=0;
}
}
if (chan[0].freqChanged || chan[0].keyOn || chan[0].keyOff) {
//DivInstrument* ins=parent->getIns(chan[0].ins,DIV_INS_AMIGA);
double off=1.0;
if (!chan[0].useWave && chan[0].sample>=0 && chan[0].sample<parent->song.sampleLen) {
DivSample* s=parent->getSample(chan[0].sample);
off=(s->centerRate>=1)?((double)s->centerRate/parent->getCenterRate()):1.0;
}
chan[0].freq=off*parent->calcFreq(chan[0].baseFreq,chan[0].pitch,chan[0].fixedArp?chan[0].baseNoteOverride:chan[0].arpOff,chan[0].fixedArp,false,2,chan[0].pitch2,chipClock,CHIP_FREQBASE);
if (chan[0].freq>16777215) chan[0].freq=16777215;
if (chan[0].keyOn) {
if (!chan[0].std.vol.had) {
chan[0].envVol=64;
if (NEW_ARP_STRAT) {
chan[i].handleArp();
} else if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
chan[i].baseFreq=NOTE_FREQUENCY(parent->calcArp(chan[i].note,chan[i].std.arp.val));
}
chan[0].keyOn=false;
chan[i].freqChanged=true;
}
if (chan[0].keyOff) {
chan[0].keyOff=false;
if (chan[i].useWave && chan[i].std.wave.had) {
if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) {
chan[i].wave=chan[i].std.wave.val;
chan[i].ws.changeWave1(chan[i].wave);
if (!chan[i].keyOff) chan[i].keyOn=true;
}
}
if (chan[i].useWave && chan[i].active) {
chan[i].ws.tick();
}
if (chan[i].std.pitch.had) {
if (chan[i].std.pitch.mode) {
chan[i].pitch2+=chan[i].std.pitch.val;
CLAMP_VAR(chan[i].pitch2,-32768,32767);
} else {
chan[i].pitch2=chan[i].std.pitch.val;
}
chan[i].freqChanged=true;
}
if (chan[i].std.panL.had) {
int val=chan[i].std.panL.val&0x7f;
chan[i].panL=val*2;
}
if (chan[i].std.panR.had) {
int val=chan[i].std.panR.val&0x7f;
chan[i].panR=val*2;
}
if (chan[i].std.phaseReset.had) {
if (chan[i].std.phaseReset.val==1) {
chan[i].audDir=false;
chan[i].audPos=0;
}
}
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
//DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AMIGA);
double off=1.0;
if (!chan[i].useWave && chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) {
DivSample* s=parent->getSample(chan[i].sample);
off=(s->centerRate>=1)?((double)s->centerRate/parent->getCenterRate()):1.0;
}
chan[i].freq=off*parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE);
if (chan[i].freq>16777215) chan[i].freq=16777215;
if (chan[i].keyOn) {
if (!chan[i].std.vol.had) {
chan[i].envVol=64;
}
chan[i].keyOn=false;
}
if (chan[i].keyOff) {
chan[i].keyOff=false;
}
chan[i].freqChanged=false;
}
chan[0].freqChanged=false;
}
}
int DivPlatformPCMDAC::dispatch(DivCommand c) {
if (c.chan>=chans) return 0;
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[0].ins,DIV_INS_AMIGA);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
if (ins->amiga.useWave) {
chan[c.chan].sampleNote=DIV_NOTE_NULL;
chan[c.chan].sampleNoteDelta=0;
chan[0].useWave=true;
chan[0].audLen=ins->amiga.waveLen+1;
if (chan[0].insChanged) {
if (chan[0].wave<0) {
chan[0].wave=0;
chan[0].ws.setWidth(chan[0].audLen);
chan[0].ws.changeWave1(chan[0].wave);
chan[c.chan].useWave=true;
chan[c.chan].audLen=ins->amiga.waveLen+1;
if (chan[c.chan].insChanged) {
if (chan[c.chan].wave<0) {
chan[c.chan].wave=0;
chan[c.chan].ws.setWidth(chan[c.chan].audLen);
chan[c.chan].ws.changeWave1(chan[c.chan].wave);
}
}
} else {
if (c.value!=DIV_NOTE_NULL) {
chan[0].sample=ins->amiga.getSample(c.value);
chan[c.chan].sample=ins->amiga.getSample(c.value);
chan[c.chan].sampleNote=c.value;
c.value=ins->amiga.getFreq(c.value);
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
@ -340,120 +372,120 @@ int DivPlatformPCMDAC::dispatch(DivCommand c) {
chan[c.chan].sample=ins->amiga.getSample(chan[c.chan].sampleNote);
c.value=ins->amiga.getFreq(chan[c.chan].sampleNote);
}
chan[0].useWave=false;
chan[c.chan].useWave=false;
}
if (c.value!=DIV_NOTE_NULL) {
chan[0].baseFreq=round(NOTE_FREQUENCY(c.value));
chan[c.chan].baseFreq=round(NOTE_FREQUENCY(c.value));
}
if (chan[0].useWave || chan[0].sample<0 || chan[0].sample>=parent->song.sampleLen) {
chan[0].sample=-1;
if (chan[c.chan].useWave || chan[c.chan].sample<0 || chan[c.chan].sample>=parent->song.sampleLen) {
chan[c.chan].sample=-1;
chan[c.chan].sampleNote=DIV_NOTE_NULL;
chan[c.chan].sampleNoteDelta=0;
}
if (chan[0].setPos) {
chan[0].setPos=false;
if (chan[c.chan].setPos) {
chan[c.chan].setPos=false;
} else {
chan[0].audDir=false;
chan[0].audPos=0;
chan[c.chan].audDir=false;
chan[c.chan].audPos=0;
}
chan[0].audSub=0;
memset(chan[0].audDat,0,8*sizeof(short));
chan[c.chan].audSub=0;
memset(chan[c.chan].audDat,0,8*sizeof(short));
if (c.value!=DIV_NOTE_NULL) {
chan[0].freqChanged=true;
chan[0].note=c.value;
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
}
chan[0].active=true;
chan[0].keyOn=true;
chan[0].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[0].std.vol.will) {
chan[0].envVol=64;
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].envVol=64;
}
if (chan[0].useWave) {
chan[0].ws.init(ins,chan[0].audLen,255,chan[0].insChanged);
if (chan[c.chan].useWave) {
chan[c.chan].ws.init(ins,chan[c.chan].audLen,255,chan[c.chan].insChanged);
}
chan[0].insChanged=false;
chan[c.chan].insChanged=false;
break;
}
case DIV_CMD_NOTE_OFF:
chan[0].sample=-1;
chan[0].active=false;
chan[0].keyOff=true;
chan[0].macroInit(NULL);
chan[c.chan].sample=-1;
chan[c.chan].active=false;
chan[c.chan].keyOff=true;
chan[c.chan].macroInit(NULL);
break;
case DIV_CMD_NOTE_OFF_ENV:
case DIV_CMD_ENV_RELEASE:
chan[0].std.release();
chan[c.chan].std.release();
break;
case DIV_CMD_INSTRUMENT:
if (chan[0].ins!=c.value || c.value2==1) {
chan[0].ins=c.value;
chan[0].insChanged=true;
if (chan[c.chan].ins!=c.value || c.value2==1) {
chan[c.chan].ins=c.value;
chan[c.chan].insChanged=true;
}
break;
case DIV_CMD_VOLUME:
if (chan[0].vol!=c.value) {
chan[0].vol=c.value;
if (!chan[0].std.vol.has) {
chan[0].envVol=64;
if (chan[c.chan].vol!=c.value) {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.vol.has) {
chan[c.chan].envVol=64;
}
}
break;
case DIV_CMD_GET_VOLUME:
return chan[0].vol;
return chan[c.chan].vol;
break;
case DIV_CMD_PANNING:
chan[0].panL=c.value;
chan[0].panR=c.value2;
chan[c.chan].panL=c.value;
chan[c.chan].panR=c.value2;
break;
case DIV_CMD_PITCH:
chan[0].pitch=c.value;
chan[0].freqChanged=true;
chan[c.chan].pitch=c.value;
chan[c.chan].freqChanged=true;
break;
case DIV_CMD_WAVE:
if (!chan[0].useWave) break;
chan[0].wave=c.value;
chan[0].keyOn=true;
chan[0].ws.changeWave1(chan[0].wave);
if (!chan[c.chan].useWave) break;
chan[c.chan].wave=c.value;
chan[c.chan].keyOn=true;
chan[c.chan].ws.changeWave1(chan[c.chan].wave);
break;
case DIV_CMD_NOTE_PORTA: {
int destFreq=round(NOTE_FREQUENCY(c.value2+chan[c.chan].sampleNoteDelta));
bool return2=false;
if (destFreq>chan[0].baseFreq) {
chan[0].baseFreq+=c.value;
if (chan[0].baseFreq>=destFreq) {
chan[0].baseFreq=destFreq;
if (destFreq>chan[c.chan].baseFreq) {
chan[c.chan].baseFreq+=c.value;
if (chan[c.chan].baseFreq>=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
}
} else {
chan[0].baseFreq-=c.value;
if (chan[0].baseFreq<=destFreq) {
chan[0].baseFreq=destFreq;
chan[c.chan].baseFreq-=c.value;
if (chan[c.chan].baseFreq<=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
}
}
chan[0].freqChanged=true;
chan[c.chan].freqChanged=true;
if (return2) {
chan[0].inPorta=false;
chan[c.chan].inPorta=false;
return 2;
}
break;
}
case DIV_CMD_LEGATO: {
chan[0].baseFreq=round(NOTE_FREQUENCY(c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[0].std.arp.val):(0))));
chan[0].freqChanged=true;
chan[0].note=c.value;
chan[c.chan].baseFreq=round(NOTE_FREQUENCY(c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0))));
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
break;
}
case DIV_CMD_PRE_PORTA:
if (chan[0].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[0].macroInit(parent->getIns(chan[0].ins,DIV_INS_AMIGA));
if (chan[c.chan].active && c.value2) {
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
}
chan[0].inPorta=c.value;
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_SAMPLE_POS:
if (chan[0].useWave) break;
chan[0].audPos=c.value;
chan[0].setPos=true;
if (chan[c.chan].useWave) break;
chan[c.chan].audPos=c.value;
chan[c.chan].setPos=true;
break;
case DIV_CMD_GET_VOLMAX:
return volMax;
@ -474,31 +506,38 @@ int DivPlatformPCMDAC::dispatch(DivCommand c) {
}
void DivPlatformPCMDAC::muteChannel(int ch, bool mute) {
isMuted=mute;
if (ch>=chans) return;
isMuted[ch]=mute;
}
void DivPlatformPCMDAC::forceIns() {
chan[0].insChanged=true;
chan[0].freqChanged=true;
chan[0].audDir=false;
chan[0].audPos=0;
chan[0].sample=-1;
for (int i=0; i<chans; i++) {
chan[i].insChanged=true;
chan[i].freqChanged=true;
chan[i].audDir=false;
chan[i].audPos=0;
chan[i].sample=-1;
}
}
void* DivPlatformPCMDAC::getChanState(int ch) {
return &chan;
if (ch>=chans) return NULL;
return &chan[ch];
}
DivDispatchOscBuffer* DivPlatformPCMDAC::getOscBuffer(int ch) {
return oscBuf;
if (ch>=chans) return NULL;
return &oscBuf[ch];
}
void DivPlatformPCMDAC::reset() {
chan[0]=DivPlatformPCMDAC::Channel();
chan[0].std.setEngine(parent);
chan[0].ws.setEngine(parent);
chan[0].ws.init(NULL,32,255);
memset(chan[0].audDat,0,8*sizeof(short));
for (int i=0; i<chans; i++) {
chan[i]=DivPlatformPCMDAC::Channel();
chan[i].std.setEngine(parent);
chan[i].ws.setEngine(parent);
chan[i].ws.init(NULL,32,255);
memset(chan[i].audDat,0,8*sizeof(short));
}
}
int DivPlatformPCMDAC::getOutputCount() {
@ -506,15 +545,17 @@ int DivPlatformPCMDAC::getOutputCount() {
}
DivMacroInt* DivPlatformPCMDAC::getChanMacroInt(int ch) {
return &chan[0].std;
if (ch>=chans) return NULL;
return &chan[ch].std;
}
unsigned short DivPlatformPCMDAC::getPan(int ch) {
return (chan[0].panL<<8)|chan[0].panR;
if (ch>=chans) return 0;
return (chan[ch].panL<<8)|chan[ch].panR;
}
DivSamplePos DivPlatformPCMDAC::getSamplePos(int ch) {
if (ch>=1) return DivSamplePos();
if (ch>=chans) return DivSamplePos();
return DivSamplePos(
chan[ch].sample,
chan[ch].audPos,
@ -523,19 +564,25 @@ DivSamplePos DivPlatformPCMDAC::getSamplePos(int ch) {
}
void DivPlatformPCMDAC::notifyInsChange(int ins) {
if (chan[0].ins==ins) {
chan[0].insChanged=true;
for (int i=0; i<chans; i++) {
if (chan[i].ins==ins) {
chan[i].insChanged=true;
}
}
}
void DivPlatformPCMDAC::notifyWaveChange(int wave) {
if (chan[0].useWave && chan[0].wave==wave) {
chan[0].ws.changeWave1(wave);
for (int i=0; i<chans; i++) {
if (chan[i].useWave && chan[i].wave==wave) {
chan[i].ws.changeWave1(wave);
}
}
}
void DivPlatformPCMDAC::notifyInsDeletion(void* ins) {
chan[0].std.notifyInsDeletion((DivInstrument*)ins);
for (int i=0; i<chans; i++) {
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
}
}
void DivPlatformPCMDAC::setFlags(const DivConfig& flags) {
@ -547,22 +594,38 @@ void DivPlatformPCMDAC::setFlags(const DivConfig& flags) {
outDepth=(flags.getInt("outDepth",15))&15;
outStereo=flags.getBool("stereo",true);
interp=flags.getInt("interpolation",0);
oscBuf->setRate(rate);
for (int i=0; i<chans; i++) {
oscBuf[i].setRate(rate);
}
volMax=flags.getInt("volMax",255);
if (volMax<1) volMax=1;
volMult=flags.getFloat("volMult",1.0f);
if (volMult<0.0f) volMult=0.0f;
if (volMult>1.0f) volMult=1.0f;
}
int DivPlatformPCMDAC::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
parent=p;
dumpWrites=false;
skipRegisterWrites=false;
oscBuf=new DivDispatchOscBuffer;
isMuted=false;
oscBuf=new DivDispatchOscBuffer[channels];
chan=new Channel[channels];
isMuted=new bool[channels];
chans=channels;
for (int i=0; i<channels; i++) {
isMuted[i]=false;
}
setFlags(flags);
reset();
return 1;
}
void DivPlatformPCMDAC::quit() {
delete oscBuf;
delete[] chan;
delete[] isMuted;
delete[] oscBuf;
chan=NULL;
isMuted=NULL;
oscBuf=NULL;
chans=0;
}

View file

@ -52,9 +52,10 @@ class DivPlatformPCMDAC: public DivDispatch {
setPos(false),
envVol(64) {}
};
Channel chan[1];
Channel* chan;
bool* isMuted;
int chans;
DivDispatchOscBuffer* oscBuf;
bool isMuted;
int outDepth;
// valid values:
// - 0: none
@ -64,6 +65,7 @@ class DivPlatformPCMDAC: public DivDispatch {
int interp;
int volMax;
bool outStereo;
float volMult;
friend void putDispatchChip(void*,int);
friend void putDispatchChan(void*,int,int);
@ -87,6 +89,8 @@ class DivPlatformPCMDAC: public DivDispatch {
void notifyInsDeletion(void* ins);
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
void quit();
DivPlatformPCMDAC():
chan(NULL), isMuted(NULL), chans(0) {}
};
#endif

View file

@ -470,7 +470,7 @@ int DivPlatformPCSpeaker::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER));
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
break;
@ -537,9 +537,9 @@ int DivPlatformPCSpeaker::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -158,7 +158,7 @@ int DivPlatformPET::dispatch(DivCommand c) {
chan[0].active=true;
chan[0].keyOn=true;
chan[0].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[0].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[0].std.vol.will) {
chan[0].outVol=chan[0].vol;
}
break;
@ -227,9 +227,9 @@ int DivPlatformPET::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[0].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[0].macroInit(parent->getIns(chan[0].ins,DIV_INS_PET));
if (parent->song.compatFlags.resetMacroOnPorta) chan[0].macroInit(parent->getIns(chan[0].ins,DIV_INS_PET));
}
if (!chan[0].inPorta && c.value && !parent->song.brokenPortaArp && chan[0].std.arp.will && !NEW_ARP_STRAT) chan[0].baseFreq=NOTE_PERIODIC(chan[0].note);
if (!chan[0].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[0].std.arp.will && !NEW_ARP_STRAT) chan[0].baseFreq=NOTE_PERIODIC(chan[0].note);
chan[0].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -175,7 +175,7 @@ int DivPlatformPokeMini::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_POKEMINI));
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
break;
@ -241,9 +241,9 @@ int DivPlatformPokeMini::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_POKEMINI));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_POKEMINI));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -184,7 +184,7 @@ void DivPlatformPOKEY::tick(bool sysTick) {
for (int i=0; i<4; i++) {
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,parent->song.linearPitch?chan[i].pitch:0,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,0,parent->song.linearPitch?chan[i].pitch2:0,chipClock,CHIP_DIVIDER);
chan[i].freq=parent->calcFreq(chan[i].baseFreq,parent->song.compatFlags.linearPitch?chan[i].pitch:0,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,0,parent->song.compatFlags.linearPitch?chan[i].pitch2:0,chipClock,CHIP_DIVIDER);
if ((i==0 && !(audctl&64)) || (i==2 && !(audctl&32)) || i==1 || i==3) {
chan[i].freq/=7;
@ -223,7 +223,7 @@ void DivPlatformPOKEY::tick(bool sysTick) {
}
// non-linear pitch
if (!parent->song.linearPitch) {
if (!parent->song.compatFlags.linearPitch) {
chan[i].freq-=chan[i].pitch;
}
@ -297,7 +297,7 @@ int DivPlatformPOKEY::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
chan[c.chan].ctlChanged=true;
}
@ -383,9 +383,9 @@ int DivPlatformPOKEY::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_POKEY));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_POKEY));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -101,7 +101,7 @@ int DivPlatformPong::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER));
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
break;
@ -168,9 +168,9 @@ int DivPlatformPong::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -288,7 +288,7 @@ int DivPlatformPowerNoise::dispatch(DivCommand c) {
}
chan[c.chan].active=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
chan[c.chan].keyOn=true;
@ -372,9 +372,9 @@ int DivPlatformPowerNoise::dispatch(DivCommand c) {
}
case DIV_CMD_PRE_PORTA: {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_POWERNOISE));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_POWERNOISE));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) {
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) {
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
}
chan[c.chan].inPorta=c.value;

View file

@ -182,9 +182,9 @@ int DivPlatformPV1000::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_PV1000));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_PV1000));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -488,7 +488,7 @@ int DivPlatformQSound::dispatch(DivCommand c) {
chan[c.chan].keyOn=true;
chan[c.chan].keyOff=false;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
if (chan[c.chan].isNewQSound) {
chan[c.chan].resVol=(chan[c.chan].outVol*16383)/255;
@ -594,9 +594,9 @@ int DivPlatformQSound::dispatch(DivCommand c) {
}
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=QS_NOTE_FREQUENCY(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=QS_NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_SAMPLE_POS:

View file

@ -210,7 +210,7 @@ int DivPlatformRF5C68::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
break;
@ -284,9 +284,9 @@ int DivPlatformRF5C68::dispatch(DivCommand c) {
}
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_SAMPLE_POS:

View file

@ -211,7 +211,7 @@ int DivPlatformSAA1099::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (isMuted[c.chan]) {
@ -261,13 +261,13 @@ int DivPlatformSAA1099::dispatch(DivCommand c) {
int destFreq=NOTE_PERIODIC(c.value2);
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {
chan[c.chan].baseFreq+=c.value*((parent->song.linearPitch)?1:(8-chan[c.chan].freqH));
chan[c.chan].baseFreq+=c.value*((parent->song.compatFlags.linearPitch)?1:(8-chan[c.chan].freqH));
if (chan[c.chan].baseFreq>=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
}
} else {
chan[c.chan].baseFreq-=c.value*((parent->song.linearPitch)?1:(8-chan[c.chan].freqH));
chan[c.chan].baseFreq-=c.value*((parent->song.compatFlags.linearPitch)?1:(8-chan[c.chan].freqH));
if (chan[c.chan].baseFreq<=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
@ -318,9 +318,9 @@ int DivPlatformSAA1099::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SAA1099));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SAA1099));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_PRE_NOTE:

View file

@ -172,7 +172,7 @@ int DivPlatformSCC::dispatch(DivCommand c) {
}
chan[c.chan].active=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (!isMuted[c.chan]) {
@ -253,9 +253,9 @@ int DivPlatformSCC::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SCC));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SCC));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -100,7 +100,7 @@ void DivPlatformSCV::tick(bool sysTick) {
} else {
chan[i].freq=(chan[i].baseFreq+chan[i].pitch+chan[i].pitch2+143);
}
if (!parent->song.oldArpStrategy) {
if (!parent->song.compatFlags.oldArpStrategy) {
if (chan[i].fixedArp) {
chan[i].freq=(chan[i].baseNoteOverride)+chan[i].pitch+chan[i].pitch2;
} else {
@ -186,7 +186,7 @@ int DivPlatformSCV::dispatch(DivCommand c) {
chan[c.chan].keyOn=true;
//chwrite(c.chan,0x04,0x80|chan[c.chan].vol);
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
chan[c.chan].insChanged=false;
@ -267,9 +267,9 @@ int DivPlatformSCV::dispatch(DivCommand c) {
}
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_UPD1771C));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_UPD1771C));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) {
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) {
chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
}
chan[c.chan].inPorta=c.value;

View file

@ -66,7 +66,7 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
for (int i=0; i<16; i++) {
chan[i].std.next();
if (parent->song.newSegaPCM) {
if (parent->song.compatFlags.newSegaPCM) {
if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul;
chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127;
@ -89,13 +89,13 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
chan[i].pcm.freq=-1;
}
if (parent->song.newSegaPCM) if (chan[i].std.panL.had) {
if (parent->song.compatFlags.newSegaPCM) if (chan[i].std.panL.had) {
chan[i].chPanL=chan[i].std.panL.val&127;
chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127;
rWrite(2+(i<<3),chan[i].chVolL);
}
if (parent->song.newSegaPCM) if (chan[i].std.panR.had) {
if (parent->song.compatFlags.newSegaPCM) if (chan[i].std.panR.had) {
chan[i].chPanR=chan[i].std.panR.val&127;
chan[i].chVolR=(chan[i].outVol*chan[i].chPanR)/127;
rWrite(3+(i<<3),chan[i].chVolR);
@ -120,7 +120,7 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
chan[i].freq=chan[i].baseFreq+(chan[i].pitch)-128+(oldSlides?0:chan[i].pitch2);
if (!parent->song.oldArpStrategy) {
if (!parent->song.compatFlags.oldArpStrategy) {
if (chan[i].fixedArp) {
chan[i].freq=(chan[i].baseNoteOverride<<7)+chan[i].pitch-128+(chan[i].pitch2<<(oldSlides?1:0));
} else {
@ -204,10 +204,10 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
chan[c.chan].pcm.freq=-1;
}
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
if (parent->song.newSegaPCM) {
if (parent->song.compatFlags.newSegaPCM) {
chan[c.chan].chVolL=(chan[c.chan].outVol*chan[c.chan].chPanL)/127;
chan[c.chan].chVolR=(chan[c.chan].outVol*chan[c.chan].chPanR)/127;
rWrite(2+(c.chan<<3),chan[c.chan].chVolL);
@ -240,7 +240,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
if (parent->song.newSegaPCM) {
if (parent->song.compatFlags.newSegaPCM) {
chan[c.chan].chVolL=(c.value*chan[c.chan].chPanL)/127;
chan[c.chan].chVolR=(c.value*chan[c.chan].chPanR)/127;
} else {
@ -262,7 +262,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
chan[c.chan].ins=c.value;
break;
case DIV_CMD_PANNING: {
if (parent->song.newSegaPCM) {
if (parent->song.compatFlags.newSegaPCM) {
chan[c.chan].chPanL=c.value>>1;
chan[c.chan].chPanR=c.value2>>1;
chan[c.chan].chVolL=(chan[c.chan].outVol*chan[c.chan].chPanL)/127;
@ -284,7 +284,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
case DIV_CMD_NOTE_PORTA: {
int destFreq=((c.value2+chan[c.chan].sampleNoteDelta)<<7);
int newFreq;
int mul=(oldSlides || !parent->song.linearPitch)?8:1;
int mul=(oldSlides || !parent->song.compatFlags.linearPitch)?8:1;
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {
newFreq=chan[c.chan].baseFreq+c.value*mul;
@ -334,7 +334,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
return 127;
break;
case DIV_CMD_PRE_PORTA:
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=(chan[c.chan].note<<7);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=(chan[c.chan].note<<7);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_PRE_NOTE:

View file

@ -445,12 +445,12 @@ int DivPlatformSID2::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta || parent->song.preNoteNoEffect) {
if (parent->song.compatFlags.resetMacroOnPorta || parent->song.compatFlags.preNoteNoEffect) {
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SID2));
chan[c.chan].keyOn=true;
}
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -845,7 +845,7 @@ int DivPlatformSID3::dispatch(DivCommand c) {
}
chan[c.chan].active=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
//chan[c.chan].keyOn=true;
@ -997,12 +997,12 @@ int DivPlatformSID3::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta || parent->song.preNoteNoEffect) {
if (parent->song.compatFlags.resetMacroOnPorta || parent->song.compatFlags.preNoteNoEffect) {
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SID3));
chan[c.chan].keyOn=true;
}
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_PANNING: {

View file

@ -208,7 +208,7 @@ int DivPlatformSM8521::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (chan[c.chan].wave<0) {
@ -267,13 +267,13 @@ int DivPlatformSM8521::dispatch(DivCommand c) {
int destFreq=NOTE_PERIODIC(c.value2);
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {
chan[c.chan].baseFreq+=c.value*((parent->song.linearPitch)?1:8);
chan[c.chan].baseFreq+=c.value*((parent->song.compatFlags.linearPitch)?1:8);
if (chan[c.chan].baseFreq>=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
}
} else {
chan[c.chan].baseFreq-=c.value*((parent->song.linearPitch)?1:8);
chan[c.chan].baseFreq-=c.value*((parent->song.compatFlags.linearPitch)?1:8);
if (chan[c.chan].baseFreq<=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
@ -293,9 +293,9 @@ int DivPlatformSM8521::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SM8521));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SM8521));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -190,7 +190,7 @@ void DivPlatformSMS::acquireDirect(blip_buffer_t** bb, size_t len) {
double DivPlatformSMS::NOTE_SN(int ch, int note) {
double CHIP_DIVIDER=toneDivider;
if (ch==3) CHIP_DIVIDER=noiseDivider;
if (parent->song.linearPitch || !easyNoise) {
if (parent->song.compatFlags.linearPitch || !easyNoise) {
return NOTE_PERIODIC(note);
}
int easyStartingPeriod=16;
@ -210,7 +210,7 @@ int DivPlatformSMS::snCalcFreq(int ch) {
if (chan[ch].fixedArp) {
curFreq=chan[ch].baseNoteOverride<<7;
}
if (parent->song.linearPitch && easyNoise && curFreq>easyThreshold) {
if (parent->song.compatFlags.linearPitch && easyNoise && curFreq>easyThreshold) {
int ret=(((easyStartingPeriod<<7))-(curFreq-(easyThreshold)))>>7;
if (ret<0) ret=0;
return ret;
@ -242,7 +242,7 @@ void DivPlatformSMS::tick(bool sysTick) {
}
if (i==3) {
if (chan[i].std.duty.had) {
if (chan[i].std.duty.val!=snNoiseMode || parent->song.snDutyReset) {
if (chan[i].std.duty.val!=snNoiseMode || parent->song.compatFlags.snDutyReset) {
snNoiseMode=chan[i].std.duty.val;
if (chan[i].std.duty.val<2) {
chan[3].freqChanged=false;
@ -277,7 +277,7 @@ void DivPlatformSMS::tick(bool sysTick) {
if (chan[i].freqChanged) {
chan[i].freq=snCalcFreq(i);
if (chan[i].freq>1023) chan[i].freq=1023;
if (parent->song.snNoLowPeriods) {
if (parent->song.compatFlags.snNoLowPeriods) {
if (chan[i].freq<8) chan[i].freq=1;
} else {
if (chan[i].freq<0) chan[i].freq=0;
@ -297,7 +297,7 @@ void DivPlatformSMS::tick(bool sysTick) {
chan[3].freq=snCalcFreq(3);
//parent->calcFreq(chan[3].baseFreq,chan[3].pitch,chan[3].fixedArp?chan[3].baseNoteOverride:chan[3].arpOff,chan[3].fixedArp,true,0,chan[3].pitch2,chipClock,noiseDivider);
if (chan[3].freq>1023) chan[3].freq=1023;
if (parent->song.snNoLowPeriods) {
if (parent->song.compatFlags.snNoLowPeriods) {
if (chan[3].actualNote>0x5d) chan[3].freq=0x01;
}
if (chan[3].freq<0) chan[3].freq=0;
@ -359,13 +359,13 @@ int DivPlatformSMS::dispatch(DivCommand c) {
}
chan[c.chan].active=true;
chan[c.chan].keyOff=false;
//if (!parent->song.brokenOutVol2) {
//if (!parent->song.compatFlags.brokenOutVol2) {
chan[c.chan].writeVol=true;
chan[c.chan].outVol=chan[c.chan].vol;
//rWrite(0,0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15))));
//}
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
break;
@ -451,9 +451,9 @@ int DivPlatformSMS::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_SN(c.chan,chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_SN(c.chan,chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -390,7 +390,7 @@ int DivPlatformSNES::dispatch(DivCommand c) {
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
// this is the fix. it needs testing.
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
if (chan[c.chan].outVol!=chan[c.chan].vol) chan[c.chan].shallWriteVol=true;
chan[c.chan].outVol=chan[c.chan].vol;
}
@ -482,7 +482,7 @@ int DivPlatformSNES::dispatch(DivCommand c) {
}
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SNES));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SNES));
}
chan[c.chan].inPorta=c.value;
break;

View file

@ -327,7 +327,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
chan[c.chan].hwSeqDelay=0;
chWrite(c.chan,0x02,chan[c.chan].vol);
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
chan[c.chan].insChanged=false;
@ -484,13 +484,13 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
int destFreq=NOTE_SU(c.chan,c.value2+chan[c.chan].sampleNoteDelta);
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {
chan[c.chan].baseFreq+=c.value*((parent->song.linearPitch)?1:(1+(chan[c.chan].baseFreq>>9)));
chan[c.chan].baseFreq+=c.value*((parent->song.compatFlags.linearPitch)?1:(1+(chan[c.chan].baseFreq>>9)));
if (chan[c.chan].baseFreq>=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
}
} else {
chan[c.chan].baseFreq-=c.value*((parent->song.linearPitch)?1:(1+(chan[c.chan].baseFreq>>9)));
chan[c.chan].baseFreq-=c.value*((parent->song.compatFlags.linearPitch)?1:(1+(chan[c.chan].baseFreq>>9)));
if (chan[c.chan].baseFreq<=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
@ -519,9 +519,9 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SU));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SU));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_SU(c.chan,chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_SU(c.chan,chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_C64_PW_SLIDE:

View file

@ -297,7 +297,7 @@ int DivPlatformSupervision::dispatch(DivCommand c) {
chan[c.chan].keyOn=true;
//chwrite(c.chan,0x04,0x80|chan[c.chan].vol);
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
chan[c.chan].insChanged=false;
@ -384,9 +384,9 @@ int DivPlatformSupervision::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SUPERVISION));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SUPERVISION));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -405,7 +405,7 @@ int DivPlatformSwan::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (chan[c.chan].wave<0) {
@ -538,9 +538,9 @@ int DivPlatformSwan::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SWAN));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SWAN));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -95,7 +95,7 @@ void DivPlatformT6W28::writeOutVol(int ch) {
double DivPlatformT6W28::NOTE_SN(int ch, int note) {
double CHIP_DIVIDER=16;
if (ch==3) CHIP_DIVIDER=15;
if (parent->song.linearPitch || !easyNoise) {
if (parent->song.compatFlags.linearPitch || !easyNoise) {
return NOTE_PERIODIC(note);
}
if (note>107) {
@ -105,7 +105,7 @@ double DivPlatformT6W28::NOTE_SN(int ch, int note) {
}
int DivPlatformT6W28::snCalcFreq(int ch) {
if (parent->song.linearPitch && easyNoise && chan[ch].baseFreq+chan[ch].pitch+chan[ch].pitch2>(107<<7)) {
if (parent->song.compatFlags.linearPitch && easyNoise && chan[ch].baseFreq+chan[ch].pitch+chan[ch].pitch2>(107<<7)) {
int ret=(((13<<7)+0x40)-(chan[ch].baseFreq+chan[ch].pitch+chan[ch].pitch2-(107<<7)))>>7;
if (ret<0) ret=0;
return ret;
@ -187,7 +187,7 @@ int DivPlatformT6W28::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
writeOutVol(c.chan);
}
@ -270,9 +270,9 @@ int DivPlatformT6W28::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_T6W28));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_T6W28));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_SN(c.chan,chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_SN(c.chan,chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -149,7 +149,7 @@ int DivPlatformTED::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
chan[c.chan].insChanged=false;
@ -230,9 +230,9 @@ int DivPlatformTED::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_TED));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_TED));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -295,7 +295,7 @@ int DivPlatformTIA::dispatch(DivCommand c) {
chan[c.chan].keyOn=true;
rWrite(0x15+c.chan,chan[c.chan].shape);
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (chan[c.chan].insChanged) {
@ -395,7 +395,7 @@ int DivPlatformTIA::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_TIA));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_TIA));
}
chan[c.chan].inPorta=c.value;
break;

View file

@ -229,7 +229,7 @@ void DivPlatformTX81Z::tick(bool sysTick) {
if (chan[i].std.alg.had) {
chan[i].state.alg=chan[i].std.alg.val;
immWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|(chan[i].active?0x40:0)|(chan[i].chVolR<<7));
if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) {
if (!parent->song.compatFlags.algMacroBehavior) for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
if (isMuted[i] || !op.enable) {
@ -321,7 +321,7 @@ void DivPlatformTX81Z::tick(bool sysTick) {
}
// fixed pitch
if (parent->song.linearPitch) {
if (parent->song.compatFlags.linearPitch) {
bool freqChangeOp=false;
if (op.egt) {
@ -416,7 +416,7 @@ void DivPlatformTX81Z::tick(bool sysTick) {
for (int i=0; i<8; i++) {
if (chan[i].freqChanged) {
chan[i].freq=chan[i].baseFreq+chan[i].pitch-128+chan[i].pitch2;
if (!parent->song.oldArpStrategy) {
if (!parent->song.compatFlags.oldArpStrategy) {
if (chan[i].fixedArp) {
chan[i].freq=(chan[i].baseNoteOverride<<7)+chan[i].pitch-128+chan[i].pitch2;
} else {
@ -1006,7 +1006,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) {
return 127;
break;
case DIV_CMD_PRE_PORTA:
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_LINEAR(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_LINEAR(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_PRE_NOTE:

View file

@ -297,7 +297,7 @@ int DivPlatformVB::dispatch(DivCommand c) {
}
chWrite(4,0x00,0x80);
}
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
writeEnv(c.chan);
}
@ -445,9 +445,9 @@ int DivPlatformVB::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_PCE));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_PCE));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -347,7 +347,7 @@ int DivPlatformVERA::dispatch(DivCommand c) {
}
chan[c.chan].active=true;
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VERA));
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
break;
@ -421,7 +421,7 @@ int DivPlatformVERA::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VERA));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VERA));
}
if (!chan[c.chan].inPorta && c.value && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=calcNoteFreq(c.chan,chan[c.chan].note);
chan[c.chan].inPorta=c.value;

View file

@ -247,9 +247,9 @@ int DivPlatformVIC20::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VIC));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VIC));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -297,7 +297,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
}
chan[c.chan].active=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
//chan[c.chan].keyOn=true;
@ -418,9 +418,9 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VRC6));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VRC6));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -614,7 +614,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
chan[c.chan].keyOn=true;
chan[c.chan].envChanged=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (chan[c.chan].wave<0) {
@ -729,9 +729,9 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_X1_010));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_X1_010));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NoteX1_010(c.chan,chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NoteX1_010(c.chan,chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_SAMPLE_FREQ:

View file

@ -551,7 +551,7 @@ void DivPlatformYM2203::tick(bool sysTick) {
if (chan[i].std.alg.had) {
chan[i].state.alg=chan[i].std.alg.val;
rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) {
if (!parent->song.compatFlags.algMacroBehavior) for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
if (isMuted[i] || !op.enable) {
@ -661,7 +661,7 @@ void DivPlatformYM2203::tick(bool sysTick) {
for (int i=0; i<3; i++) {
if (i==2 && extMode) continue;
if (chan[i].freqChanged) {
if (parent->song.linearPitch) {
if (parent->song.compatFlags.linearPitch) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11,chan[i].state.block);
} else {
int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,4,chan[i].pitch2);
@ -797,7 +797,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) {
chan[c.chan].keyOff=true;
chan[c.chan].keyOn=false;
chan[c.chan].active=false;
if (parent->song.brokenFMOff) chan[c.chan].macroInit(NULL);
if (parent->song.compatFlags.brokenFMOff) chan[c.chan].macroInit(NULL);
break;
case DIV_CMD_NOTE_OFF_ENV:
chan[c.chan].keyOff=true;
@ -867,7 +867,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) {
}
break;
}
if (c.chan>(psgChanOffs-1) || parent->song.linearPitch) { // PSG
if (c.chan>(psgChanOffs-1) || parent->song.compatFlags.linearPitch) { // PSG
int destFreq=NOTE_FNUM_BLOCK(c.value2,11,chan[c.chan].state.block);
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {
@ -1156,7 +1156,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) {
case DIV_CMD_PRE_PORTA:
if (c.chan>(2+isCSM)) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM));
}
}
chan[c.chan].inPorta=c.value;

View file

@ -146,7 +146,7 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) {
break;
}
case DIV_CMD_NOTE_PORTA: {
if (parent->song.linearPitch) {
if (parent->song.compatFlags.linearPitch) {
int destFreq=NOTE_FREQUENCY(c.value2);
bool return2=false;
if (destFreq>opChan[ch].baseFreq) {
@ -472,7 +472,7 @@ void DivPlatformYM2203Ext::tick(bool sysTick) {
if (opChan[i].std.alg.had) {
chan[extChanOffs].state.alg=opChan[i].std.alg.val;
rWrite(chanOffs[extChanOffs]+ADDR_FB_ALG,(chan[extChanOffs].state.alg&7)|(chan[extChanOffs].state.fb<<3));
if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) {
if (!parent->song.compatFlags.algMacroBehavior) for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[j];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[j];
if (isOpMuted[j] || !op.enable) {
@ -551,7 +551,7 @@ void DivPlatformYM2203Ext::tick(bool sysTick) {
unsigned char hardResetMask=0;
if (extMode) for (int i=0; i<4; i++) {
if (opChan[i].freqChanged) {
if (parent->song.linearPitch) {
if (parent->song.compatFlags.linearPitch) {
opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch,opChan[i].fixedArp?opChan[i].baseNoteOverride:opChan[i].arpOff,opChan[i].fixedArp,false,4,opChan[i].pitch2,chipClock,CHIP_FREQBASE,11,chan[extChanOffs].state.block);
} else {
int fNum=parent->calcFreq(opChan[i].baseFreq&0x7ff,opChan[i].pitch,opChan[i].fixedArp?opChan[i].baseNoteOverride:opChan[i].arpOff,opChan[i].fixedArp,false,4,opChan[i].pitch2);

View file

@ -794,7 +794,7 @@ void DivPlatformYM2608::tick(bool sysTick) {
if (chan[i].std.alg.had) {
chan[i].state.alg=chan[i].std.alg.val;
rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) {
if (!parent->song.compatFlags.algMacroBehavior) for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
if (isMuted[i] || !op.enable) {
@ -916,7 +916,7 @@ void DivPlatformYM2608::tick(bool sysTick) {
for (int i=0; i<6; i++) {
if (i==2 && extMode) continue;
if (chan[i].freqChanged) {
if (parent->song.linearPitch) {
if (parent->song.compatFlags.linearPitch) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11,chan[i].state.block);
} else {
int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,4,chan[i].pitch2);
@ -1238,7 +1238,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
chan[c.chan].keyOff=true;
chan[c.chan].keyOn=false;
chan[c.chan].active=false;
if (parent->song.brokenFMOff) chan[c.chan].macroInit(NULL);
if (parent->song.compatFlags.brokenFMOff) chan[c.chan].macroInit(NULL);
break;
case DIV_CMD_NOTE_OFF_ENV:
chan[c.chan].keyOff=true;
@ -1340,7 +1340,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
}
break;
}
if (c.chan>(5+isCSM) || parent->song.linearPitch) { // PSG, ADPCM-B
if (c.chan>(5+isCSM) || parent->song.compatFlags.linearPitch) { // PSG, ADPCM-B
int destFreq=NOTE_OPNB(c.chan,c.value2+chan[c.chan].sampleNoteDelta);
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {
@ -1651,7 +1651,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
case DIV_CMD_PRE_PORTA:
if (c.chan>5) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM));
}
}
chan[c.chan].inPorta=c.value;

View file

@ -150,7 +150,7 @@ int DivPlatformYM2608Ext::dispatch(DivCommand c) {
} else {
opChan[ch].pan=(c.value2>0)|((c.value>0)<<1);
}
if (parent->song.sharedExtStat) {
if (parent->song.compatFlags.sharedExtStat) {
for (int i=0; i<4; i++) {
if (ch==i) continue;
opChan[i].pan=opChan[ch].pan;
@ -166,7 +166,7 @@ int DivPlatformYM2608Ext::dispatch(DivCommand c) {
break;
}
case DIV_CMD_NOTE_PORTA: {
if (parent->song.linearPitch) {
if (parent->song.compatFlags.linearPitch) {
int destFreq=NOTE_FREQUENCY(c.value2);
bool return2=false;
if (destFreq>opChan[ch].baseFreq) {
@ -510,7 +510,7 @@ void DivPlatformYM2608Ext::tick(bool sysTick) {
if (opChan[i].std.alg.had) {
chan[extChanOffs].state.alg=opChan[i].std.alg.val;
rWrite(chanOffs[extChanOffs]+ADDR_FB_ALG,(chan[extChanOffs].state.alg&7)|(chan[extChanOffs].state.fb<<3));
if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) {
if (!parent->song.compatFlags.algMacroBehavior) for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[j];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[j];
if (isOpMuted[j] || !op.enable) {
@ -541,7 +541,7 @@ void DivPlatformYM2608Ext::tick(bool sysTick) {
if (opChan[i].std.panL.had) {
opChan[i].pan=opChan[i].std.panL.val&3;
if (parent->song.sharedExtStat) {
if (parent->song.compatFlags.sharedExtStat) {
for (int j=0; j<4; j++) {
if (i==j) continue;
opChan[j].pan=opChan[i].pan;
@ -612,7 +612,7 @@ void DivPlatformYM2608Ext::tick(bool sysTick) {
unsigned char hardResetMask=0;
if (extMode) for (int i=0; i<4; i++) {
if (opChan[i].freqChanged) {
if (parent->song.linearPitch) {
if (parent->song.compatFlags.linearPitch) {
opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch,opChan[i].fixedArp?opChan[i].baseNoteOverride:opChan[i].arpOff,opChan[i].fixedArp,false,4,opChan[i].pitch2,chipClock,CHIP_FREQBASE,11,chan[extChanOffs].state.block);
} else {
int fNum=parent->calcFreq(opChan[i].baseFreq&0x7ff,opChan[i].pitch,opChan[i].fixedArp?opChan[i].baseNoteOverride:opChan[i].arpOff,opChan[i].fixedArp,false,4,opChan[i].pitch2);

View file

@ -714,7 +714,7 @@ void DivPlatformYM2610::tick(bool sysTick) {
if (chan[i].std.alg.had) {
chan[i].state.alg=chan[i].std.alg.val;
rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) {
if (!parent->song.compatFlags.algMacroBehavior) for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
if (isMuted[i] || !op.enable) {
@ -836,7 +836,7 @@ void DivPlatformYM2610::tick(bool sysTick) {
for (int i=0; i<(psgChanOffs-isCSM); i++) {
if (i==1 && extMode) continue;
if (chan[i].freqChanged) {
if (parent->song.linearPitch) {
if (parent->song.compatFlags.linearPitch) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11,chan[i].state.block);
} else {
int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11);
@ -1178,7 +1178,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
chan[c.chan].keyOff=true;
chan[c.chan].keyOn=false;
chan[c.chan].active=false;
if (parent->song.brokenFMOff) chan[c.chan].macroInit(NULL);
if (parent->song.compatFlags.brokenFMOff) chan[c.chan].macroInit(NULL);
break;
case DIV_CMD_NOTE_OFF_ENV:
chan[c.chan].keyOff=true;
@ -1280,7 +1280,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
}
break;
}
if (c.chan>=psgChanOffs || parent->song.linearPitch) { // PSG, ADPCM-B
if (c.chan>=psgChanOffs || parent->song.compatFlags.linearPitch) { // PSG, ADPCM-B
int destFreq=NOTE_OPNB(c.chan,c.value2+chan[c.chan].sampleNoteDelta);
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {
@ -1591,7 +1591,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
case DIV_CMD_PRE_PORTA:
if (c.chan>=psgChanOffs) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM));
}
}
chan[c.chan].inPorta=c.value;

View file

@ -783,7 +783,7 @@ void DivPlatformYM2610B::tick(bool sysTick) {
if (chan[i].std.alg.had) {
chan[i].state.alg=chan[i].std.alg.val;
rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) {
if (!parent->song.compatFlags.algMacroBehavior) for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
if (isMuted[i] || !op.enable) {
@ -905,7 +905,7 @@ void DivPlatformYM2610B::tick(bool sysTick) {
for (int i=0; i<(psgChanOffs-isCSM); i++) {
if (i==2 && extMode) continue;
if (chan[i].freqChanged) {
if (parent->song.linearPitch) {
if (parent->song.compatFlags.linearPitch) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11,chan[i].state.block);
} else {
int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,4,chan[i].pitch2);
@ -1247,7 +1247,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
chan[c.chan].keyOff=true;
chan[c.chan].keyOn=false;
chan[c.chan].active=false;
if (parent->song.brokenFMOff) chan[c.chan].macroInit(NULL);
if (parent->song.compatFlags.brokenFMOff) chan[c.chan].macroInit(NULL);
break;
case DIV_CMD_NOTE_OFF_ENV:
chan[c.chan].keyOff=true;
@ -1349,7 +1349,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
}
break;
}
if (c.chan>=psgChanOffs || parent->song.linearPitch) { // PSG, ADPCM-B
if (c.chan>=psgChanOffs || parent->song.compatFlags.linearPitch) { // PSG, ADPCM-B
int destFreq=NOTE_OPNB(c.chan,c.value2+chan[c.chan].sampleNoteDelta);
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {
@ -1660,7 +1660,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
case DIV_CMD_PRE_PORTA:
if (c.chan>=psgChanOffs) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM));
}
}
chan[c.chan].inPorta=c.value;

View file

@ -146,7 +146,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
} else {
opChan[ch].pan=(c.value2>0)|((c.value>0)<<1);
}
if (parent->song.sharedExtStat) {
if (parent->song.compatFlags.sharedExtStat) {
for (int i=0; i<4; i++) {
if (ch==i) continue;
opChan[i].pan=opChan[ch].pan;
@ -162,7 +162,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
break;
}
case DIV_CMD_NOTE_PORTA: {
if (parent->song.linearPitch) {
if (parent->song.compatFlags.linearPitch) {
int destFreq=NOTE_FREQUENCY(c.value2);
bool return2=false;
if (destFreq>opChan[ch].baseFreq) {
@ -503,7 +503,7 @@ void DivPlatformYM2610BExt::tick(bool sysTick) {
if (opChan[i].std.alg.had) {
chan[extChanOffs].state.alg=opChan[i].std.alg.val;
rWrite(chanOffs[extChanOffs]+ADDR_FB_ALG,(chan[extChanOffs].state.alg&7)|(chan[extChanOffs].state.fb<<3));
if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) {
if (!parent->song.compatFlags.algMacroBehavior) for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[j];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[j];
if (isOpMuted[j] || !op.enable) {
@ -534,7 +534,7 @@ void DivPlatformYM2610BExt::tick(bool sysTick) {
if (opChan[i].std.panL.had) {
opChan[i].pan=opChan[i].std.panL.val&3;
if (parent->song.sharedExtStat) {
if (parent->song.compatFlags.sharedExtStat) {
for (int j=0; j<4; j++) {
if (i==j) continue;
opChan[j].pan=opChan[i].pan;
@ -604,7 +604,7 @@ void DivPlatformYM2610BExt::tick(bool sysTick) {
unsigned char hardResetMask=0;
if (extMode) for (int i=0; i<4; i++) {
if (opChan[i].freqChanged) {
if (parent->song.linearPitch) {
if (parent->song.compatFlags.linearPitch) {
opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch,opChan[i].fixedArp?opChan[i].baseNoteOverride:opChan[i].arpOff,opChan[i].fixedArp,false,4,opChan[i].pitch2,chipClock,CHIP_FREQBASE,11,chan[extChanOffs].state.block);
} else {
int fNum=parent->calcFreq(opChan[i].baseFreq&0x7ff,opChan[i].pitch,opChan[i].fixedArp?opChan[i].baseNoteOverride:opChan[i].arpOff,opChan[i].fixedArp,false,4,opChan[i].pitch2);

View file

@ -146,7 +146,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
} else {
opChan[ch].pan=(c.value2>0)|((c.value>0)<<1);
}
if (parent->song.sharedExtStat) {
if (parent->song.compatFlags.sharedExtStat) {
for (int i=0; i<4; i++) {
if (ch==i) continue;
opChan[i].pan=opChan[ch].pan;
@ -162,7 +162,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
break;
}
case DIV_CMD_NOTE_PORTA: {
if (parent->song.linearPitch) {
if (parent->song.compatFlags.linearPitch) {
int destFreq=NOTE_FREQUENCY(c.value2);
bool return2=false;
if (destFreq>opChan[ch].baseFreq) {
@ -503,7 +503,7 @@ void DivPlatformYM2610Ext::tick(bool sysTick) {
if (opChan[i].std.alg.had) {
chan[extChanOffs].state.alg=opChan[i].std.alg.val;
rWrite(chanOffs[extChanOffs]+ADDR_FB_ALG,(chan[extChanOffs].state.alg&7)|(chan[extChanOffs].state.fb<<3));
if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) {
if (!parent->song.compatFlags.algMacroBehavior) for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[j];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[j];
if (isOpMuted[j] || !op.enable) {
@ -534,7 +534,7 @@ void DivPlatformYM2610Ext::tick(bool sysTick) {
if (opChan[i].std.panL.had) {
opChan[i].pan=opChan[i].std.panL.val&3;
if (parent->song.sharedExtStat) {
if (parent->song.compatFlags.sharedExtStat) {
for (int j=0; j<4; j++) {
if (i==j) continue;
opChan[j].pan=opChan[i].pan;
@ -604,7 +604,7 @@ void DivPlatformYM2610Ext::tick(bool sysTick) {
unsigned char hardResetMask=0;
if (extMode) for (int i=0; i<4; i++) {
if (opChan[i].freqChanged) {
if (parent->song.linearPitch) {
if (parent->song.compatFlags.linearPitch) {
opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch,opChan[i].fixedArp?opChan[i].baseNoteOverride:opChan[i].arpOff,opChan[i].fixedArp,false,4,opChan[i].pitch2,chipClock,CHIP_FREQBASE,11,chan[extChanOffs].state.block);
} else {
int fNum=parent->calcFreq(opChan[i].baseFreq&0x7ff,opChan[i].pitch,opChan[i].fixedArp?opChan[i].baseNoteOverride:opChan[i].arpOff,opChan[i].fixedArp,false,4,opChan[i].pitch2);

View file

@ -241,7 +241,7 @@ int DivPlatformYMZ280B::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
break;
@ -287,7 +287,7 @@ int DivPlatformYMZ280B::dispatch(DivCommand c) {
case DIV_CMD_NOTE_PORTA: {
int destFreq=NOTE_FREQUENCY(c.value2+chan[c.chan].sampleNoteDelta);
bool return2=false;
int multiplier=(parent->song.linearPitch)?1:256;
int multiplier=(parent->song.compatFlags.linearPitch)?1:256;
if (destFreq>chan[c.chan].baseFreq) {
chan[c.chan].baseFreq+=c.value*multiplier;
if (chan[c.chan].baseFreq>=destFreq) {
@ -316,9 +316,9 @@ int DivPlatformYMZ280B::dispatch(DivCommand c) {
}
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_SAMPLE_POS:

View file

@ -212,9 +212,9 @@ int DivPlatformZXBeeper::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER));
if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
if (!chan[c.chan].inPorta && c.value && !parent->song.compatFlags.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

Some files were not shown because too many files have changed in this diff Show more