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:
commit
6ad8a0893b
131 changed files with 5673 additions and 3997 deletions
152
src/engine/assetDir.cpp
Normal file
152
src/engine/assetDir.cpp
Normal 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
52
src/engine/assetDir.h
Normal 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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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; \
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ int DivPlatformZXBeeperQuadTone::dispatch(DivCommand c) {
|
|||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].macroInit(ins);
|
||||
chan[c.chan].insChanged=false;
|
||||
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);
|
||||
}
|
||||
|
|
@ -293,9 +293,9 @@ int DivPlatformZXBeeperQuadTone::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_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:
|
||||
|
|
|
|||
|
|
@ -496,18 +496,23 @@ int DivEngine::dispatchCmd(DivCommand c) {
|
|||
}
|
||||
}
|
||||
|
||||
// don't dispatch if the channel doesn't exist
|
||||
if (song.dispatchChanOfChan[c.dis]<0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// map the channel to channel of chip
|
||||
// c.dis is a copy of c.chan because we'll use it in the next call
|
||||
c.chan=dispatchChanOfChan[c.dis];
|
||||
c.chan=song.dispatchChanOfChan[c.dis];
|
||||
|
||||
// dispatch command to chip dispatch
|
||||
return disCont[dispatchOfChan[c.dis]].dispatch->dispatch(c);
|
||||
return disCont[song.dispatchOfChan[c.dis]].dispatch->dispatch(c);
|
||||
}
|
||||
|
||||
// this function handles per-chip normal effects
|
||||
bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effectVal) {
|
||||
// don't process invalid chips
|
||||
DivSysDef* sysDef=sysDefs[sysOfChan[ch]];
|
||||
DivSysDef* sysDef=sysDefs[song.sysOfChan[ch]];
|
||||
if (sysDef==NULL) return false;
|
||||
// find the effect handler
|
||||
auto iter=sysDef->effectHandlers.find(effect);
|
||||
|
|
@ -530,7 +535,7 @@ bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effe
|
|||
// this handles per-chip post effects...
|
||||
bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal) {
|
||||
// don't process invalid chips
|
||||
DivSysDef* sysDef=sysDefs[sysOfChan[ch]];
|
||||
DivSysDef* sysDef=sysDefs[song.sysOfChan[ch]];
|
||||
if (sysDef==NULL) return false;
|
||||
// find the effect handler
|
||||
auto iter=sysDef->postEffectHandlers.find(effect);
|
||||
|
|
@ -552,7 +557,7 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
|
|||
|
||||
// ...and this handles chip pre-effects
|
||||
bool DivEngine::perSystemPreEffect(int ch, unsigned char effect, unsigned char effectVal) {
|
||||
DivSysDef* sysDef=sysDefs[sysOfChan[ch]];
|
||||
DivSysDef* sysDef=sysDefs[song.sysOfChan[ch]];
|
||||
if (sysDef==NULL) return false;
|
||||
auto iter=sysDef->preEffectHandlers.find(effect);
|
||||
if (iter==sysDef->preEffectHandlers.end()) return false;
|
||||
|
|
@ -659,9 +664,9 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
// - 2: DefleMask (same as 1)
|
||||
// in the case of normal, the jump row (changePos) is not reset to 0
|
||||
// this means that you can do 0Dxx 0Byy and it'll work, taking you to row xx of order yy
|
||||
if (changeOrd==-1 || song.jumpTreatment==0) {
|
||||
if (changeOrd==-1 || song.compatFlags.jumpTreatment==0) {
|
||||
changeOrd=effectVal;
|
||||
if (song.jumpTreatment==1 || song.jumpTreatment==2) {
|
||||
if (song.compatFlags.jumpTreatment==1 || song.compatFlags.jumpTreatment==2) {
|
||||
changePos=0;
|
||||
}
|
||||
}
|
||||
|
|
@ -671,23 +676,23 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
// if there is a 0Dxx effect on the very last order, it is ignored
|
||||
|
||||
// COMPAT FLAG: simultaneous jump treatment
|
||||
if (song.jumpTreatment==2) {
|
||||
if (song.compatFlags.jumpTreatment==2) {
|
||||
// - 2: DefleMask (jump to next order unless it is the last one and ignoreJumpAtEnd is on)
|
||||
if ((curOrder<(curSubSong->ordersLen-1) || !song.ignoreJumpAtEnd)) {
|
||||
if ((curOrder<(curSubSong->ordersLen-1) || !song.compatFlags.ignoreJumpAtEnd)) {
|
||||
// changeOrd -2 means increase order by 1
|
||||
// it overrides a previous 0Bxx effect
|
||||
changeOrd=-2;
|
||||
changePos=effectVal;
|
||||
}
|
||||
} else if (song.jumpTreatment==1) {
|
||||
} else if (song.compatFlags.jumpTreatment==1) {
|
||||
// - 1: old Furnace (same as 2 but ignored if 0Bxx is present)
|
||||
if (changeOrd<0 && (curOrder<(curSubSong->ordersLen-1) || !song.ignoreJumpAtEnd)) {
|
||||
if (changeOrd<0 && (curOrder<(curSubSong->ordersLen-1) || !song.compatFlags.ignoreJumpAtEnd)) {
|
||||
changeOrd=-2;
|
||||
changePos=effectVal;
|
||||
}
|
||||
} else {
|
||||
// - 0: normal
|
||||
if (curOrder<(curSubSong->ordersLen-1) || !song.ignoreJumpAtEnd) {
|
||||
if (curOrder<(curSubSong->ordersLen-1) || !song.compatFlags.ignoreJumpAtEnd) {
|
||||
// set the target order if not set, allowing you to use 0B and 0D regardless of position
|
||||
if (changeOrd<0) {
|
||||
changeOrd=-2;
|
||||
|
|
@ -700,13 +705,13 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
if (effectVal!=0) {
|
||||
// COMPAT FLAG: cut/delay effect policy (delayBehavior)
|
||||
// - 0: strict
|
||||
// - delays equal or greater to the speed * timeBase are ignored
|
||||
// - delays equal or greater to the speed are ignored (formerly time base was involved but that has been removed now)
|
||||
// - 1: strict old
|
||||
// - delays equal or greater to the speed are ignored
|
||||
// - delays greater to the speed are ignored
|
||||
// - 2: lax (default)
|
||||
// - no delay is ever ignored unless overridden by another
|
||||
bool comparison=(song.delayBehavior==1)?(effectVal<=nextSpeed):(effectVal<(nextSpeed*(curSubSong->timeBase+1)));
|
||||
if (song.delayBehavior==2) comparison=true;
|
||||
bool comparison=(song.compatFlags.delayBehavior==1)?(effectVal<=nextSpeed):(effectVal<(nextSpeed));
|
||||
if (song.compatFlags.delayBehavior==2) comparison=true;
|
||||
if (comparison) {
|
||||
// set the delay row, order and timer
|
||||
chan[i].rowDelay=effectVal;
|
||||
|
|
@ -721,7 +726,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
// this hack is disabled due to its dirtiness and the fact I
|
||||
// don't feel like being compatible with a buggy tracker any further
|
||||
if (effectVal==nextSpeed) {
|
||||
//if (sysOfChan[i]!=DIV_SYSTEM_YM2610 && sysOfChan[i]!=DIV_SYSTEM_YM2610_EXT) chan[i].delayLocked=true;
|
||||
//if (song.sysOfChan[i]!=DIV_SYSTEM_YM2610 && song.sysOfChan[i]!=DIV_SYSTEM_YM2610_EXT) chan[i].delayLocked=true;
|
||||
} else {
|
||||
chan[i].delayLocked=false;
|
||||
}
|
||||
|
|
@ -757,7 +762,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
|
||||
// COMPAT FLAG: legacy volume slides
|
||||
// - sets volume to max once a vol slide down has finished (thus setting volume to volMax+1)
|
||||
if (song.legacyVolumeSlides && chan[i].volume==chan[i].volMax+1) {
|
||||
if (song.compatFlags.legacyVolumeSlides && chan[i].volume==chan[i].volMax+1) {
|
||||
logV("forcing volume");
|
||||
chan[i].volume=chan[i].volMax;
|
||||
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
||||
|
|
@ -775,7 +780,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
// COMPAT FLAG: reset slides on note off (inverted in the GUI)
|
||||
// - a portamento/pitch slide will be halted upon encountering note off
|
||||
// - this will not occur if the stopPortaOnNoteOff flag is on and this is a portamento
|
||||
if (chan[i].inPorta && song.noteOffResetsSlides) {
|
||||
if (chan[i].inPorta && song.compatFlags.noteOffResetsSlides) {
|
||||
// stopOnOff will be false if stopPortaOnNoteOff flag is off
|
||||
if (chan[i].stopOnOff) {
|
||||
chan[i].portaNote=-1;
|
||||
|
|
@ -784,15 +789,10 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
chan[i].stopOnOff=false;
|
||||
}
|
||||
// depending on the system, portamento may still be disabled
|
||||
if (disCont[dispatchOfChan[i]].dispatch->keyOffAffectsPorta(dispatchChanOfChan[i])) {
|
||||
if (song.dispatchChanOfChan[i]>=0) if (disCont[song.dispatchOfChan[i]].dispatch->keyOffAffectsPorta(song.dispatchChanOfChan[i])) {
|
||||
chan[i].portaNote=-1;
|
||||
chan[i].portaSpeed=-1;
|
||||
dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0)));
|
||||
// this here is a now-disabled hack which makes the noise channel also stop when square 3 is
|
||||
/*if (i==2 && sysOfChan[i]==DIV_SYSTEM_SMS) {
|
||||
chan[i+1].portaNote=-1;
|
||||
chan[i+1].portaSpeed=-1;
|
||||
}*/
|
||||
}
|
||||
// another compatibility hack which schedules a second reset later just in case
|
||||
chan[i].scheduledSlideReset=true;
|
||||
|
|
@ -805,21 +805,17 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
chan[i].keyOn=false;
|
||||
chan[i].keyOff=true;
|
||||
// same thing here regarding reset slide behavior
|
||||
if (chan[i].inPorta && song.noteOffResetsSlides) {
|
||||
if (chan[i].inPorta && song.compatFlags.noteOffResetsSlides) {
|
||||
if (chan[i].stopOnOff) {
|
||||
chan[i].portaNote=-1;
|
||||
chan[i].portaSpeed=-1;
|
||||
dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0)));
|
||||
chan[i].stopOnOff=false;
|
||||
}
|
||||
if (disCont[dispatchOfChan[i]].dispatch->keyOffAffectsPorta(dispatchChanOfChan[i])) {
|
||||
if (song.dispatchChanOfChan[i]>=0) if (disCont[song.dispatchOfChan[i]].dispatch->keyOffAffectsPorta(song.dispatchChanOfChan[i])) {
|
||||
chan[i].portaNote=-1;
|
||||
chan[i].portaSpeed=-1;
|
||||
dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0)));
|
||||
/*if (i==2 && sysOfChan[i]==DIV_SYSTEM_SMS) {
|
||||
chan[i+1].portaNote=-1;
|
||||
chan[i+1].portaSpeed=-1;
|
||||
}*/
|
||||
}
|
||||
chan[i].scheduledSlideReset=true;
|
||||
}
|
||||
|
|
@ -839,7 +835,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
// ...unless there's a way to trigger keyOn twice
|
||||
if (!chan[i].keyOn) {
|
||||
// the behavior of arpeggio reset upon note off varies per system
|
||||
if (disCont[dispatchOfChan[i]].dispatch->keyOffAffectsArp(dispatchChanOfChan[i])) {
|
||||
if (song.dispatchChanOfChan[i]>=0) if (disCont[song.dispatchOfChan[i]].dispatch->keyOffAffectsArp(song.dispatchChanOfChan[i])) {
|
||||
chan[i].arp=0;
|
||||
dispatchCmd(DivCommand(DIV_CMD_HINT_ARPEGGIO,i,chan[i].arp));
|
||||
}
|
||||
|
|
@ -847,7 +843,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
chan[i].doNote=true;
|
||||
// COMPAT FLAG: compatible arpeggio
|
||||
// - once a new note plays, arp will not be applied for this tick
|
||||
if (chan[i].arp!=0 && song.compatibleArpeggio) {
|
||||
if (chan[i].arp!=0 && song.compatFlags.compatibleArpeggio) {
|
||||
chan[i].arpYield=true;
|
||||
}
|
||||
}
|
||||
|
|
@ -876,7 +872,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
// COMPAT FLAG: legacy ALWAYS_SET_VOLUME behavior (oldAlwaysSetVolume)
|
||||
// - prior to its addition, volume changes wouldn't be effective depending on the system if the volume is the same as the current one
|
||||
// - afterwards, volume change is made regardless in order to set the bottom byte of volume ("subvolume")
|
||||
if (!song.oldAlwaysSetVolume || disCont[dispatchOfChan[i]].dispatch->getLegacyAlwaysSetVolume() || (MIN(chan[i].volMax,chan[i].volume)>>8)!=pat->newData[whatRow][DIV_PAT_VOL]) {
|
||||
if (!song.compatFlags.oldAlwaysSetVolume || disCont[song.dispatchOfChan[i]].dispatch->getLegacyAlwaysSetVolume() || (MIN(chan[i].volMax,chan[i].volume)>>8)!=pat->newData[whatRow][DIV_PAT_VOL]) {
|
||||
// here we let dispatchCmd() know we can do MIDI aftertouch if there isn't a note
|
||||
if (pat->newData[whatRow][DIV_PAT_NOTE]==-1) {
|
||||
chan[i].midiAftertouch=true;
|
||||
|
|
@ -986,7 +982,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
// - 02xx still works
|
||||
// - a previous portamento (03xx) will prevent this slide from occurring
|
||||
// - E1xy/E2xy also will if *another* flag is set
|
||||
if (song.ignoreDuplicateSlides && (lastSlide==0x01 || lastSlide==0x1337)) break;
|
||||
if (song.compatFlags.ignoreDuplicateSlides && (lastSlide==0x01 || lastSlide==0x1337)) break;
|
||||
lastSlide=0x01;
|
||||
if (effectVal==0) {
|
||||
chan[i].portaNote=-1;
|
||||
|
|
@ -998,12 +994,12 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
// - this prompts dispatch to stop processing arp macros during a slide
|
||||
// - this only happens if pitch linearity is set to None
|
||||
// - if we don't let dispatch know, the slide will never occur as arp takes over
|
||||
if (!song.arpNonPorta) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0));
|
||||
if (!song.compatFlags.arpNonPorta) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0));
|
||||
} else {
|
||||
// COMPAT FLAG: limit slide range
|
||||
// - this confines pitch slides from dispatch->getPortaFloor to C-8 (I think)
|
||||
// - yep, the lowest portamento note depends on the system...
|
||||
chan[i].portaNote=song.limitSlides?0x60:255;
|
||||
chan[i].portaNote=song.compatFlags.limitSlides?0x60:255;
|
||||
chan[i].portaSpeed=effectVal;
|
||||
dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0)));
|
||||
// most of these are used for compat flag handling
|
||||
|
|
@ -1017,7 +1013,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
// - this prompts dispatch to stop processing arp macros during a slide
|
||||
// - this only happens if pitch linearity is set to None
|
||||
// - if we don't let dispatch know, the slide will never occur as arp takes over
|
||||
if (!song.arpNonPorta) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,true,0));
|
||||
if (!song.compatFlags.arpNonPorta) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,true,0));
|
||||
}
|
||||
break;
|
||||
case 0x02: // pitch slide down
|
||||
|
|
@ -1026,7 +1022,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
// - 01xx still works
|
||||
// - a previous portamento (03xx) will prevent this slide from occurring
|
||||
// - E1xy/E2xy also will if *another* flag is set
|
||||
if (song.ignoreDuplicateSlides && (lastSlide==0x02 || lastSlide==0x1337)) break;
|
||||
if (song.compatFlags.ignoreDuplicateSlides && (lastSlide==0x02 || lastSlide==0x1337)) break;
|
||||
lastSlide=0x02;
|
||||
if (effectVal==0) {
|
||||
chan[i].portaNote=-1;
|
||||
|
|
@ -1034,12 +1030,12 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0)));
|
||||
chan[i].inPorta=false;
|
||||
// COMPAT FLAG: arpeggio inhibits non-porta slides
|
||||
if (!song.arpNonPorta) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0));
|
||||
if (!song.compatFlags.arpNonPorta) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0));
|
||||
} else {
|
||||
// COMPAT FLAG: limit slide range
|
||||
// - this confines pitch slides from dispatch->getPortaFloor to C-8 (I think)
|
||||
// - yep, the lowest portamento note depends on the system...
|
||||
chan[i].portaNote=song.limitSlides?disCont[dispatchOfChan[i]].dispatch->getPortaFloor(dispatchChanOfChan[i]):-60;
|
||||
chan[i].portaNote=(song.compatFlags.limitSlides && song.dispatchChanOfChan[i]>=0)?disCont[song.dispatchOfChan[i]].dispatch->getPortaFloor(song.dispatchChanOfChan[i]):-60;
|
||||
chan[i].portaSpeed=effectVal;
|
||||
dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0)));
|
||||
chan[i].portaStop=true;
|
||||
|
|
@ -1048,7 +1044,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
chan[i].wasShorthandPorta=false;
|
||||
chan[i].inPorta=false;
|
||||
// COMPAT FLAG: arpeggio inhibits non-porta slides
|
||||
if (!song.arpNonPorta) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,true,0));
|
||||
if (!song.compatFlags.arpNonPorta) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,true,0));
|
||||
}
|
||||
break;
|
||||
case 0x03: // portamento
|
||||
|
|
@ -1068,7 +1064,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
// COMPAT FLAG: buggy portamento after sliding
|
||||
// - you might want to slide up or down and then 03xx to return to the original note
|
||||
// - if a porta to the same note is attempted after slide, for some reason it does not occur
|
||||
if (chan[i].note==chan[i].oldNote && !chan[i].inPorta && song.buggyPortaAfterSlide) {
|
||||
if (chan[i].note==chan[i].oldNote && !chan[i].inPorta && song.compatFlags.buggyPortaAfterSlide) {
|
||||
chan[i].portaNote=chan[i].note;
|
||||
chan[i].portaSpeed=-1;
|
||||
} else {
|
||||
|
|
@ -1088,7 +1084,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
// COMPAT FLAG: stop portamento on note off
|
||||
// - if a portamento is called and then a note off occurs, stop portamento before the next note
|
||||
// - ...unless noteOffResetsSlides is disabled
|
||||
chan[i].stopOnOff=song.stopPortaOnNoteOff; // what?!
|
||||
chan[i].stopOnOff=song.compatFlags.stopPortaOnNoteOff; // what?!
|
||||
chan[i].scheduledSlideReset=false;
|
||||
dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,true,1));
|
||||
// this is used to inhibit any other slide commands if the respective compat flag is enabled
|
||||
|
|
@ -1148,7 +1144,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
calledPorta=true;
|
||||
// COMPAT FLAG: buggy portamento after sliding
|
||||
// yes, this also affects 06xy.
|
||||
if (chan[i].note==chan[i].oldNote && !chan[i].inPorta && song.buggyPortaAfterSlide) {
|
||||
if (chan[i].note==chan[i].oldNote && !chan[i].inPorta && song.compatFlags.buggyPortaAfterSlide) {
|
||||
chan[i].portaNote=chan[i].note;
|
||||
chan[i].portaSpeed=-1;
|
||||
} else {
|
||||
|
|
@ -1161,7 +1157,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
// this is the same as 03xx.
|
||||
chan[i].portaStop=true;
|
||||
if (chan[i].keyOn) chan[i].doNote=false;
|
||||
chan[i].stopOnOff=song.stopPortaOnNoteOff; // what?!
|
||||
chan[i].stopOnOff=song.compatFlags.stopPortaOnNoteOff; // what?!
|
||||
chan[i].scheduledSlideReset=false;
|
||||
dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,true,1));
|
||||
lastSlide=0x1337; // i hate this so much
|
||||
|
|
@ -1228,7 +1224,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
chan[i].arp=effectVal;
|
||||
// COMPAT FLAG: reset note to base on arp stop (inverted in the GUI)
|
||||
// - a 0000 effect resets arpeggio position
|
||||
if (chan[i].arp==0 && song.arp0Reset) {
|
||||
if (chan[i].arp==0 && song.compatFlags.arp0Reset) {
|
||||
chan[i].resetArp=true;
|
||||
}
|
||||
dispatchCmd(DivCommand(DIV_CMD_HINT_ARPEGGIO,i,chan[i].arp));
|
||||
|
|
@ -1250,7 +1246,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
// COMPAT FLAG: old sample offset effect
|
||||
// - before 0.6.3 the sample offset effect was 9xxx, where `xxx` is multiplied by 256
|
||||
// - the effect was then changed to 90xx/91xx/92xx, allowing you to set the low, mid and high bytes of the offset respectively
|
||||
if (song.oldSampleOffset) {
|
||||
if (song.compatFlags.oldSampleOffset) {
|
||||
// send sample position now
|
||||
dispatchCmd(DivCommand(DIV_CMD_SAMPLE_POS,i,(((effect&0x0f)<<8)|effectVal)*256));
|
||||
} else {
|
||||
|
|
@ -1283,7 +1279,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
// - ignore cut if equal or greater than speed
|
||||
// - 2: lax (default)
|
||||
// - no cut is ever ignored unless overridden by another
|
||||
if (effectVal>0 && (song.delayBehavior==2 || effectVal<nextSpeed)) {
|
||||
if (effectVal>0 && (song.compatFlags.delayBehavior==2 || effectVal<nextSpeed)) {
|
||||
// the cut timer is ticked after nextRow(), so we set it one tick higher.
|
||||
chan[i].volCut=effectVal+1;
|
||||
chan[i].cutType=0;
|
||||
|
|
@ -1324,7 +1320,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
// these are for compatibility stuff
|
||||
chan[i].portaStop=true;
|
||||
// COMPAT FLAG: stop portamento on note off
|
||||
chan[i].stopOnOff=song.stopPortaOnNoteOff; // what?!
|
||||
chan[i].stopOnOff=song.compatFlags.stopPortaOnNoteOff; // what?!
|
||||
chan[i].scheduledSlideReset=false;
|
||||
// only enter portamento if the speed is set
|
||||
if ((effectVal&15)!=0) {
|
||||
|
|
@ -1335,14 +1331,14 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
// COMPAT FLAG: broken shortcut slides
|
||||
// - oddly enough, shortcut slides are not communicated to the dispatch
|
||||
// - this was fixed in 0.5.7
|
||||
if (!song.brokenShortcutSlides) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,true,0));
|
||||
if (!song.compatFlags.brokenShortcutSlides) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,true,0));
|
||||
// COMPAT FLAG: E1xy/E2xy also take priority over slides
|
||||
// - another Defle hack. it places shortcut slides above pitch slides.
|
||||
if (song.e1e2AlsoTakePriority) lastSlide=0x1337; // ...
|
||||
if (song.compatFlags.e1e2AlsoTakePriority) lastSlide=0x1337; // ...
|
||||
} else {
|
||||
chan[i].inPorta=false;
|
||||
// COMPAT FLAG: broken shortcut slides
|
||||
if (!song.brokenShortcutSlides) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0));
|
||||
if (!song.compatFlags.brokenShortcutSlides) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0));
|
||||
}
|
||||
break;
|
||||
case 0xe2: // portamento down
|
||||
|
|
@ -1352,7 +1348,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0)));
|
||||
chan[i].portaStop=true;
|
||||
// COMPAT FLAG: stop portamento on note off
|
||||
chan[i].stopOnOff=song.stopPortaOnNoteOff; // what?!
|
||||
chan[i].stopOnOff=song.compatFlags.stopPortaOnNoteOff; // what?!
|
||||
chan[i].scheduledSlideReset=false;
|
||||
if ((effectVal&15)!=0) {
|
||||
chan[i].inPorta=true;
|
||||
|
|
@ -1360,13 +1356,13 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
chan[i].shorthandPorta=true;
|
||||
chan[i].wasShorthandPorta=true;
|
||||
// COMPAT FLAG: broken shortcut slides
|
||||
if (!song.brokenShortcutSlides) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,true,0));
|
||||
if (!song.compatFlags.brokenShortcutSlides) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,true,0));
|
||||
// COMPAT FLAG: E1xy/E2xy also take priority over slides
|
||||
if (song.e1e2AlsoTakePriority) lastSlide=0x1337; // ...
|
||||
if (song.compatFlags.e1e2AlsoTakePriority) lastSlide=0x1337; // ...
|
||||
} else {
|
||||
chan[i].inPorta=false;
|
||||
// COMPAT FLAG: broken shortcut slides
|
||||
if (!song.brokenShortcutSlides) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0));
|
||||
if (!song.compatFlags.brokenShortcutSlides) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0));
|
||||
}
|
||||
break;
|
||||
case 0xe3: // vibrato shape
|
||||
|
|
@ -1408,7 +1404,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
// - 2: lax (default)
|
||||
// - no cut is ever ignored unless overridden by another
|
||||
// "Bruh"
|
||||
if (effectVal>0 && (song.delayBehavior==2 || effectVal<nextSpeed)) {
|
||||
if (effectVal>0 && (song.compatFlags.delayBehavior==2 || effectVal<nextSpeed)) {
|
||||
// the cut timer is ticked after nextRow(), so we set it one tick higher.
|
||||
chan[i].cut=effectVal+1;
|
||||
chan[i].cutType=2;
|
||||
|
|
@ -1452,7 +1448,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
// - ignore cut if equal or greater than speed
|
||||
// - 2: lax (default)
|
||||
// - no cut is ever ignored unless overridden by another
|
||||
if (effectVal>0 && (song.delayBehavior==2 || effectVal<nextSpeed)) {
|
||||
if (effectVal>0 && (song.compatFlags.delayBehavior==2 || effectVal<nextSpeed)) {
|
||||
// the cut timer is ticked after nextRow(), so we set it one tick higher.
|
||||
chan[i].cut=effectVal+1;
|
||||
chan[i].cutType=0;
|
||||
|
|
@ -1543,7 +1539,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
// - ignore cut if equal or greater than speed
|
||||
// - 2: lax (default)
|
||||
// - no cut is ever ignored unless overridden by another
|
||||
if (song.delayBehavior==2 || effectVal<nextSpeed) {
|
||||
if (song.compatFlags.delayBehavior==2 || effectVal<nextSpeed) {
|
||||
// the cut timer is ticked after nextRow(), so we set it one tick higher.
|
||||
chan[i].cut=effectVal+1;
|
||||
chan[i].cutType=1;
|
||||
|
|
@ -1577,7 +1573,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
// COMPAT FLAG: instrument changes triggee on portamento (inverted in the GUI)
|
||||
// - before 0.6pre1 it was not possible to change instrument during portamento
|
||||
// - now it is. this sends a "null" note to allow such change
|
||||
if (insChanged && (chan[i].inPorta || calledPorta) && song.newInsTriggersInPorta) {
|
||||
if (insChanged && (chan[i].inPorta || calledPorta) && song.compatFlags.newInsTriggersInPorta) {
|
||||
dispatchCmd(DivCommand(DIV_CMD_NOTE_ON,i,DIV_NOTE_NULL));
|
||||
}
|
||||
|
||||
|
|
@ -1585,7 +1581,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
if (chan[i].doNote) {
|
||||
// COMPAT FLAG: continuous vibrato
|
||||
// - when enabled, the vibrato position is not reset on each note
|
||||
if (!song.continuousVibrato) {
|
||||
if (!song.compatFlags.continuousVibrato) {
|
||||
chan[i].vibratoPos=0;
|
||||
}
|
||||
// send pitch now (why? didn't we do that already?)
|
||||
|
|
@ -1594,7 +1590,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
// COMPAT FLAG: broken portamento during legato
|
||||
// - portamento would not occur if legato is on
|
||||
// - this was fixed in 0.6pre4
|
||||
if (chan[i].legato && (!chan[i].inPorta || song.brokenPortaLegato)) {
|
||||
if (chan[i].legato && (!chan[i].inPorta || song.compatFlags.brokenPortaLegato)) {
|
||||
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note));
|
||||
dispatchCmd(DivCommand(DIV_CMD_HINT_LEGATO,i,chan[i].note));
|
||||
} else {
|
||||
|
|
@ -1603,13 +1599,13 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
if (chan[i].inPorta && chan[i].keyOn && !chan[i].shorthandPorta) {
|
||||
// COMPAT FLAG: E1xy/E2xy stop on same note
|
||||
// - if there was a shortcut slide, stop it
|
||||
if (song.e1e2StopOnSameNote && chan[i].wasShorthandPorta) {
|
||||
if (song.compatFlags.e1e2StopOnSameNote && chan[i].wasShorthandPorta) {
|
||||
chan[i].portaSpeed=-1;
|
||||
dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0)));
|
||||
// COMPAT FLAG: broken shortcut slides
|
||||
// - oddly enough, shortcut slides are not communicated to the dispatch
|
||||
// - this was fixed in 0.5.7
|
||||
if (!song.brokenShortcutSlides) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0));
|
||||
if (!song.compatFlags.brokenShortcutSlides) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0));
|
||||
chan[i].wasShorthandPorta=false;
|
||||
chan[i].inPorta=false;
|
||||
} else {
|
||||
|
|
@ -1624,7 +1620,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
chan[i].releasing=false;
|
||||
// COMPAT FLAG: reset arp position on new note
|
||||
// - this does exactly what it says
|
||||
if (song.resetArpPhaseOnNewNote) {
|
||||
if (song.compatFlags.resetArpPhaseOnNewNote) {
|
||||
chan[i].arpStage=-1;
|
||||
}
|
||||
// these are used by VGM/ROM export to determine the duration of loop trail.
|
||||
|
|
@ -1681,10 +1677,10 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
case 0xf2: // single pitch slide down
|
||||
if (effect==0xf1) {
|
||||
// COMPAT FLAG: limit slide range
|
||||
chan[i].portaNote=song.limitSlides?0x60:255;
|
||||
chan[i].portaNote=song.compatFlags.limitSlides?0x60:255;
|
||||
} else {
|
||||
// COMPAT FLAG: limit slide range
|
||||
chan[i].portaNote=song.limitSlides?disCont[dispatchOfChan[i]].dispatch->getPortaFloor(dispatchChanOfChan[i]):-60;
|
||||
chan[i].portaNote=(song.compatFlags.limitSlides && song.dispatchChanOfChan[i]>=0)?disCont[song.dispatchOfChan[i]].dispatch->getPortaFloor(song.dispatchChanOfChan[i]):-60;
|
||||
}
|
||||
chan[i].portaSpeed=effectVal;
|
||||
chan[i].portaStop=true;
|
||||
|
|
@ -1692,13 +1688,13 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
chan[i].scheduledSlideReset=false;
|
||||
chan[i].inPorta=false;
|
||||
// COMPAT FLAG: arpeggio inhibits non-porta slides
|
||||
if (!song.arpNonPorta) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,true,0));
|
||||
dispatchCmd(DivCommand(DIV_CMD_NOTE_PORTA,i,chan[i].portaSpeed*(song.linearPitch?song.pitchSlideSpeed:1),chan[i].portaNote));
|
||||
if (!song.compatFlags.arpNonPorta) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,true,0));
|
||||
dispatchCmd(DivCommand(DIV_CMD_NOTE_PORTA,i,chan[i].portaSpeed*(song.compatFlags.linearPitch?song.compatFlags.pitchSlideSpeed:1),chan[i].portaNote));
|
||||
chan[i].portaNote=-1;
|
||||
chan[i].portaSpeed=-1;
|
||||
chan[i].inPorta=false;
|
||||
// COMPAT FLAG: arpeggio inhibits non-porta slides
|
||||
if (!song.arpNonPorta) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0));
|
||||
if (!song.compatFlags.arpNonPorta) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1726,7 +1722,7 @@ void DivEngine::nextRow() {
|
|||
if (view==DIV_STATUS_PATTERN && !skipping) {
|
||||
strcpy(pb1,"");
|
||||
strcpy(pb3,"");
|
||||
for (int i=0; i<chans; i++) {
|
||||
for (int i=0; i<song.chans; i++) {
|
||||
// orders
|
||||
snprintf(pb,4095," %.2x",curOrders->ord[i][curOrder]);
|
||||
strcat(pb1,pb);
|
||||
|
|
@ -1792,16 +1788,16 @@ void DivEngine::nextRow() {
|
|||
}
|
||||
|
||||
// process row pre on all channels
|
||||
for (int i=0; i<chans; i++) {
|
||||
for (int i=0; i<song.chans; i++) {
|
||||
// try to find pre effects
|
||||
processRowPre(i);
|
||||
}
|
||||
|
||||
// process row on all channels
|
||||
for (int i=0; i<chans; i++) {
|
||||
for (int i=0; i<song.chans; i++) {
|
||||
// COMPAT FLAG: cut/delay effect policy (delayBehavior)
|
||||
// - if not lax, reset the row delay timer so it never happens
|
||||
if (song.delayBehavior!=2) {
|
||||
if (song.compatFlags.delayBehavior!=2) {
|
||||
chan[i].rowDelay=0;
|
||||
}
|
||||
processRow(i,false);
|
||||
|
|
@ -1866,22 +1862,22 @@ void DivEngine::nextRow() {
|
|||
// - DefleMask uses a mandatory two-speed system
|
||||
// - if the pattern length is odd, the speed to use is determined correctly...
|
||||
// - ...unless the order count is also odd! in that case the first row of order 0 will always use speed 1, even if the song looped and we should be using speed 2
|
||||
if (song.brokenSpeedSel) {
|
||||
if (song.compatFlags.brokenSpeedSel) {
|
||||
unsigned char speed2=(speeds.len>=2)?speeds.val[1]:speeds.val[0];
|
||||
unsigned char speed1=speeds.val[0];
|
||||
|
||||
// if the pattern length is odd and the current order is odd, use speed 2 for even rows and speed 1 for odd ones
|
||||
if ((curSubSong->patLen&1) && curOrder&1) {
|
||||
ticks=((curRow&1)?speed2:speed1)*(curSubSong->timeBase+1);
|
||||
ticks=((curRow&1)?speed2:speed1);
|
||||
nextSpeed=(curRow&1)?speed1:speed2;
|
||||
} else {
|
||||
ticks=((curRow&1)?speed1:speed2)*(curSubSong->timeBase+1);
|
||||
ticks=((curRow&1)?speed1:speed2);
|
||||
nextSpeed=(curRow&1)?speed2:speed1;
|
||||
}
|
||||
} else {
|
||||
// normal speed alternation
|
||||
// set the number of ticks and cycle to the next speed
|
||||
ticks=speeds.val[curSpeed]*(curSubSong->timeBase+1);
|
||||
ticks=speeds.val[curSpeed];
|
||||
curSpeed++;
|
||||
if (curSpeed>=speeds.len) curSpeed=0;
|
||||
// cache the next speed for future operations
|
||||
|
|
@ -1895,7 +1891,7 @@ void DivEngine::nextRow() {
|
|||
|
||||
// post row details
|
||||
// schedule pre-notes and delays (for C64 and/or a compat flag)
|
||||
for (int i=0; i<chans; i++) {
|
||||
for (int i=0; i<song.chans; i++) {
|
||||
DivPattern* pat=curPat[i].getPattern(curOrders->ord[i][curOrder],false);
|
||||
if (pat->newData[curRow][DIV_PAT_NOTE]!=-1) {
|
||||
// if there is a note
|
||||
|
|
@ -1904,8 +1900,8 @@ void DivEngine::nextRow() {
|
|||
if (!chan[i].legato) {
|
||||
// check whether we should fire a pre-note event
|
||||
bool wantPreNote=false;
|
||||
if (disCont[dispatchOfChan[i]].dispatch!=NULL) {
|
||||
wantPreNote=disCont[dispatchOfChan[i]].dispatch->getWantPreNote();
|
||||
if (disCont[song.dispatchOfChan[i]].dispatch!=NULL) {
|
||||
wantPreNote=disCont[song.dispatchOfChan[i]].dispatch->getWantPreNote();
|
||||
if (wantPreNote) {
|
||||
bool doPreparePreNote=true;
|
||||
int addition=0;
|
||||
|
|
@ -1917,7 +1913,7 @@ void DivEngine::nextRow() {
|
|||
// COMPAT FLAG: pre-note does not take effect into consideration
|
||||
// - a bug which does not cancel pre-note before a portamento or during legato
|
||||
// - fixed in 0.6pre9
|
||||
if (!song.preNoteNoEffect) {
|
||||
if (!song.compatFlags.preNoteNoEffect) {
|
||||
// handle portamento
|
||||
if (pat->newData[curRow][DIV_PAT_FX(j)]==0x03 && pat->newData[curRow][DIV_PAT_FXVAL(j)]!=0 && pat->newData[curRow][DIV_PAT_FXVAL(j)]!=-1) {
|
||||
doPreparePreNote=false;
|
||||
|
|
@ -1951,7 +1947,7 @@ void DivEngine::nextRow() {
|
|||
|
||||
// COMPAT FLAG: auto-insert one tick gap between notes
|
||||
// - simulates behavior of certain Amiga/C64 sound drivers where a one-tick cut occurred before another note
|
||||
if (song.oneTickCut) {
|
||||
if (song.compatFlags.oneTickCut) {
|
||||
bool doPrepareCut=true;
|
||||
int addition=0;
|
||||
|
||||
|
|
@ -2039,7 +2035,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
// this is a check that nullifies any note off event that right after a note on
|
||||
// it prevents a situation where some notes do not play
|
||||
for (int i=pendingNotes.size()-1; i>=0; i--) {
|
||||
if (pendingNotes[i].channel<0 || pendingNotes[i].channel>=chans) continue;
|
||||
if (pendingNotes[i].channel<0 || pendingNotes[i].channel>=song.chans) continue;
|
||||
if (pendingNotes[i].on) {
|
||||
isOn[pendingNotes[i].channel]=true;
|
||||
} else {
|
||||
|
|
@ -2058,7 +2054,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
// fetch event
|
||||
DivNoteEvent& note=pendingNotes.front();
|
||||
// don't if channel is out of bounds or event is canceled
|
||||
if (note.nop || note.channel<0 || note.channel>=chans) {
|
||||
if (note.nop || note.channel<0 || note.channel>=song.chans) {
|
||||
pendingNotes.pop_front();
|
||||
continue;
|
||||
}
|
||||
|
|
@ -2077,10 +2073,13 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
}
|
||||
// set volume as long as there's one associated with the event
|
||||
// and the chip has per-channel volume
|
||||
if (note.volume>=0 && !disCont[dispatchOfChan[note.channel]].dispatch->isVolGlobal()) {
|
||||
if (note.volume>=0 && !disCont[song.dispatchOfChan[note.channel]].dispatch->isVolGlobal()) {
|
||||
// map velocity to curve and then to equivalent chip volume
|
||||
float curvedVol=pow((float)note.volume/127.0f,midiVolExp);
|
||||
int mappedVol=disCont[dispatchOfChan[note.channel]].dispatch->mapVelocity(dispatchChanOfChan[note.channel],curvedVol);
|
||||
int mappedVol=0;
|
||||
if (song.dispatchChanOfChan[note.channel]>=0) {
|
||||
mappedVol=disCont[song.dispatchOfChan[note.channel]].dispatch->mapVelocity(song.dispatchChanOfChan[note.channel],curvedVol);
|
||||
}
|
||||
// fire command
|
||||
dispatchCmd(DivCommand(DIV_CMD_VOLUME,note.channel,mappedVol));
|
||||
}
|
||||
|
|
@ -2094,11 +2093,14 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
chan[note.channel].lastIns=note.ins;
|
||||
} else {
|
||||
// note off
|
||||
DivMacroInt* macroInt=disCont[dispatchOfChan[note.channel]].dispatch->getChanMacroInt(dispatchChanOfChan[note.channel]);
|
||||
DivMacroInt* macroInt=NULL;
|
||||
if (song.dispatchChanOfChan[note.channel]>=0) {
|
||||
macroInt=disCont[song.dispatchOfChan[note.channel]].dispatch->getChanMacroInt(song.dispatchChanOfChan[note.channel]);
|
||||
}
|
||||
if (macroInt!=NULL) {
|
||||
// if the current instrument has a release point in any macros and
|
||||
// volume is per-channel, send a note release instead of a note off
|
||||
if (macroInt->hasRelease && !disCont[dispatchOfChan[note.channel]].dispatch->isVolGlobal()) {
|
||||
if (macroInt->hasRelease && !disCont[song.dispatchOfChan[note.channel]].dispatch->isVolGlobal()) {
|
||||
dispatchCmd(DivCommand(DIV_CMD_NOTE_OFF_ENV,note.channel));
|
||||
} else {
|
||||
dispatchCmd(DivCommand(DIV_CMD_NOTE_OFF,note.channel));
|
||||
|
|
@ -2123,7 +2125,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
// delayed row's state before it has a chance to do anything. a typical example would be
|
||||
// a delay scheduling a note-on to be simultaneous with the next row, and the next row also
|
||||
// containing a delayed note. if we don't apply the delayed row first, the world explodes.
|
||||
for (int i=0; i<chans; i++) {
|
||||
for (int i=0; i<song.chans; i++) {
|
||||
// delay effects
|
||||
if (chan[i].rowDelay>0) {
|
||||
if (--chan[i].rowDelay==0) {
|
||||
|
|
@ -2155,7 +2157,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
// - 0: reset channels. call playSub() to seek back to the loop position
|
||||
// - 1: soft-reset channels. same as 0 for now
|
||||
// - 2: don't reset
|
||||
if (song.loopModality!=2) {
|
||||
if (song.compatFlags.loopModality!=2) {
|
||||
playSub(true);
|
||||
}
|
||||
}
|
||||
|
|
@ -2188,7 +2190,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
}
|
||||
|
||||
// process stuff such as effects
|
||||
if (!shallStop) for (int i=0; i<chans; i++) {
|
||||
if (!shallStop) for (int i=0; i<song.chans; i++) {
|
||||
// retrigger
|
||||
if (chan[i].retrigSpeed) {
|
||||
if (--chan[i].retrigTick<0) {
|
||||
|
|
@ -2202,7 +2204,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
// volume slides and tremolo
|
||||
// COMPAT FLAG: don't slide on the first tick of a row
|
||||
// - Amiga/PC tracker behavior where slides and vibrato do not take course during the first tick of a row
|
||||
if (!song.noSlidesOnFirstTick || !firstTick) {
|
||||
if (!song.compatFlags.noSlidesOnFirstTick || !firstTick) {
|
||||
// volume slides
|
||||
if (chan[i].volSpeed!=0) {
|
||||
// the call to GET_VOLUME is part of a compatibility process
|
||||
|
|
@ -2252,7 +2254,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
// COMPAT FLAG: legacy volume slides
|
||||
// - sets volume to max once a vol slide down has finished (thus setting volume to volMax+1)
|
||||
// - there is more to this, such as the first step of volume macro resulting in unpredictable behavior, but I don't feel like implementing THAT...
|
||||
if (song.legacyVolumeSlides) {
|
||||
if (song.compatFlags.legacyVolumeSlides) {
|
||||
chan[i].volume=chan[i].volMax+1;
|
||||
} else {
|
||||
chan[i].volume=0;
|
||||
|
|
@ -2415,7 +2417,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
// portamento and pitch slides
|
||||
// COMPAT FLAG: don't slide on the first tick of a row
|
||||
// - Amiga/PC tracker behavior where slides and vibrato do not take course during the first tick of a row
|
||||
if (!song.noSlidesOnFirstTick || !firstTick) {
|
||||
if (!song.compatFlags.noSlidesOnFirstTick || !firstTick) {
|
||||
// portamento only runs if the channel has been used and the porta speed is higher than 0
|
||||
if ((chan[i].keyOn || chan[i].keyOff) && chan[i].portaSpeed>0) {
|
||||
// send a portamento update command to the dispatch.
|
||||
|
|
@ -2425,7 +2427,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
// - 1: full (pitch slides linear... we multiply the portamento speed by a user-defined multiplier)
|
||||
// COMPAT FLAG: reset pitch slide/portamento upon reaching target (inverted in the GUI)
|
||||
// - when disabled, portamento remains active after it has finished
|
||||
if (dispatchCmd(DivCommand(DIV_CMD_NOTE_PORTA,i,chan[i].portaSpeed*(song.linearPitch?song.pitchSlideSpeed:1),chan[i].portaNote))==2 && chan[i].portaStop && song.targetResetsSlides) {
|
||||
if (dispatchCmd(DivCommand(DIV_CMD_NOTE_PORTA,i,chan[i].portaSpeed*(song.compatFlags.linearPitch?song.compatFlags.pitchSlideSpeed:1),chan[i].portaNote))==2 && chan[i].portaStop && song.compatFlags.targetResetsSlides) {
|
||||
// if we are here, it means we reached the target and shall stop
|
||||
chan[i].portaSpeed=0;
|
||||
dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0)));
|
||||
|
|
@ -2451,7 +2453,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
// COMPAT FLAG: reset slides on note off (inverted in the GUI)
|
||||
// - a portamento/pitch slide will be halted upon encountering note off
|
||||
// - this will not occur if the stopPortaOnNoteOff flag is on and this is a portamento
|
||||
if (chan[i].inPorta && song.noteOffResetsSlides) {
|
||||
if (chan[i].inPorta && song.compatFlags.noteOffResetsSlides) {
|
||||
chan[i].keyOff=true;
|
||||
chan[i].keyOn=false;
|
||||
// stopOnOff will be false if stopPortaOnNoteOff flag is off
|
||||
|
|
@ -2462,7 +2464,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
chan[i].stopOnOff=false;
|
||||
}
|
||||
// depending on the system, portamento may still be disabled
|
||||
if (disCont[dispatchOfChan[i]].dispatch->keyOffAffectsPorta(dispatchChanOfChan[i])) {
|
||||
if (song.dispatchChanOfChan[i]>=0) if (disCont[song.dispatchOfChan[i]].dispatch->keyOffAffectsPorta(song.dispatchChanOfChan[i])) {
|
||||
chan[i].portaNote=-1;
|
||||
chan[i].portaSpeed=-1;
|
||||
dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0)));
|
||||
|
|
@ -2500,7 +2502,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
}
|
||||
// COMPAT FLAG: reset arp position on row change
|
||||
// - simulates Amiga/PC tracker behavior where the next row resets arp pos
|
||||
if (song.rowResetsArpPos && firstTick) {
|
||||
if (song.compatFlags.rowResetsArpPos && firstTick) {
|
||||
chan[i].arpStage=-1;
|
||||
}
|
||||
// arpeggio (actually)
|
||||
|
|
@ -2563,8 +2565,9 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
shallStop=false;
|
||||
shallStopSched=false;
|
||||
// reset all chan oscs
|
||||
for (int i=0; i<chans; i++) {
|
||||
DivDispatchOscBuffer* buf=disCont[dispatchOfChan[i]].dispatch->getOscBuffer(dispatchChanOfChan[i]);
|
||||
for (int i=0; i<song.chans; i++) {
|
||||
if (song.dispatchChanOfChan[i]<0) continue;
|
||||
DivDispatchOscBuffer* buf=disCont[song.dispatchOfChan[i]].dispatch->getOscBuffer(song.dispatchChanOfChan[i]);
|
||||
if (buf!=NULL) {
|
||||
buf->reset();
|
||||
}
|
||||
|
|
@ -2629,20 +2632,18 @@ void DivEngine::runMidiClock(int totalCycles) {
|
|||
output->midiOut->send(TAMidiMessage(TA_MIDI_CLOCK,0,0));
|
||||
}
|
||||
|
||||
// calculate tempo using highlight, timeBase, tick rate, speeds and virtual tempo
|
||||
// calculate tempo using highlight, tick rate, speeds and virtual tempo
|
||||
double hl=curSubSong->hilightA;
|
||||
if (hl<=0.0) hl=4.0;
|
||||
double timeBase=curSubSong->timeBase+1;
|
||||
double speedSum=0;
|
||||
double vD=virtualTempoD;
|
||||
for (int i=0; i<MIN(16,speeds.len); i++) {
|
||||
speedSum+=speeds.val[i];
|
||||
}
|
||||
speedSum/=MAX(1,speeds.len);
|
||||
if (timeBase<1.0) timeBase=1.0;
|
||||
if (speedSum<1.0) speedSum=1.0;
|
||||
if (vD<1) vD=1;
|
||||
double bpm=((24.0*divider)/(timeBase*hl*speedSum))*(double)virtualTempoN/vD;
|
||||
double bpm=((24.0*divider)/(hl*speedSum))*(double)virtualTempoN/vD;
|
||||
// avoid a division by zer
|
||||
if (bpm<1.0) bpm=1.0;
|
||||
int increment=got.rate/(bpm);
|
||||
|
|
@ -2857,7 +2858,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
|||
case TA_MIDI_NOTE_OFF: {
|
||||
if (midiIsDirect) {
|
||||
// in direct mode, map the event directly to the channel
|
||||
if (chan<0 || chan>=chans) break;
|
||||
if (chan<0 || chan>=song.chans) break;
|
||||
pendingNotes.push_back(DivNoteEvent(chan,-1,-1,-1,false,false,true));
|
||||
} else {
|
||||
// find a suitable channel and add this event to the queue
|
||||
|
|
@ -2876,7 +2877,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
|||
if (msg.data[1]==0) {
|
||||
if (midiIsDirect) {
|
||||
// in direct mode, map the event directly to the channel
|
||||
if (chan<0 || chan>=chans) break;
|
||||
if (chan<0 || chan>=song.chans) break;
|
||||
pendingNotes.push_back(DivNoteEvent(chan,-1,-1,-1,false,false,true));
|
||||
} else {
|
||||
// find a suitable channel and add this event to the queue
|
||||
|
|
@ -2885,7 +2886,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
|||
} else {
|
||||
if (midiIsDirect) {
|
||||
// in direct mode, map the event directly to the channel
|
||||
if (chan<0 || chan>=chans) break;
|
||||
if (chan<0 || chan>=song.chans) break;
|
||||
pendingNotes.push_back(DivNoteEvent(chan,ins,msg.data[0]-12,msg.data[1],true,false,true));
|
||||
} else {
|
||||
// find a suitable channel and add this event to the queue
|
||||
|
|
|
|||
|
|
@ -17,11 +17,14 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "song.h"
|
||||
#include "engine.h"
|
||||
#include "../ta-log.h"
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <chrono>
|
||||
|
||||
static DivCompatFlags defaultFlags;
|
||||
|
||||
TimeMicros DivSongTimestamps::getTimes(int order, int row) {
|
||||
if (order<0 || order>=DIV_MAX_PATTERNS) return TimeMicros(-1,0);
|
||||
if (row<0 || row>=DIV_MAX_ROWS) return TimeMicros(-1,0);
|
||||
|
|
@ -194,12 +197,12 @@ void DivSubSong::calcTimestamps(int chans, std::vector<DivGroovePattern>& groove
|
|||
if (effectVal!=0) {
|
||||
// COMPAT FLAG: cut/delay effect policy (delayBehavior)
|
||||
// - 0: strict
|
||||
// - delays equal or greater to the speed * timeBase are ignored
|
||||
// - delays equal or greater to the speed are ignored (formerly time base was involved but that has been removed now)
|
||||
// - 1: strict old
|
||||
// - delays equal or greater to the speed are ignored
|
||||
// - delays greater to the speed are ignored
|
||||
// - 2: lax (default)
|
||||
// - no delay is ever ignored unless overridden by another
|
||||
bool comparison=(delayBehavior==1)?(effectVal<=nextSpeed):(effectVal<(nextSpeed*(timeBase+1)));
|
||||
bool comparison=(delayBehavior==1)?(effectVal<=nextSpeed):(effectVal<(nextSpeed));
|
||||
if (delayBehavior==2) comparison=true;
|
||||
if (comparison) {
|
||||
// set the delay row, order and timer
|
||||
|
|
@ -324,16 +327,16 @@ void DivSubSong::calcTimestamps(int chans, std::vector<DivGroovePattern>& groove
|
|||
// we subtract firstPat from curOrder as firstPat is used by a function which finds sub-songs
|
||||
// (the beginning of a new sub-song will be in order 0)
|
||||
if ((patLen&1) && (curOrder-firstPat)&1) {
|
||||
ticks=((curRow&1)?speed2:speed1)*(timeBase+1);
|
||||
ticks=((curRow&1)?speed2:speed1);
|
||||
nextSpeed=(curRow&1)?speed1:speed2;
|
||||
} else {
|
||||
ticks=((curRow&1)?speed1:speed2)*(timeBase+1);
|
||||
ticks=((curRow&1)?speed1:speed2);
|
||||
nextSpeed=(curRow&1)?speed2:speed1;
|
||||
}
|
||||
} else {
|
||||
// normal speed alternation
|
||||
// set the number of ticks and cycle to the next speed
|
||||
ticks=curSpeeds.val[curSpeed]*(timeBase+1);
|
||||
ticks=curSpeeds.val[curSpeed];
|
||||
curSpeed++;
|
||||
if (curSpeed>=curSpeeds.len) curSpeed=0;
|
||||
// cache the next speed for future operations
|
||||
|
|
@ -448,6 +451,214 @@ void DivSubSong::calcTimestamps(int chans, std::vector<DivGroovePattern>& groove
|
|||
logV("song length: %s; %" PRIu64 " ticks",ts.totalTime.toString(6,TA_TIME_FORMAT_AUTO),ts.totalTicks);
|
||||
}
|
||||
|
||||
bool DivSubSong::readData(SafeReader& reader, int version, int chans) {
|
||||
unsigned char magic[4];
|
||||
|
||||
reader.read(magic,4);
|
||||
|
||||
if (version>=240) {
|
||||
if (memcmp(magic,"SNG2",4)!=0) {
|
||||
logE("invalid subsong header!");
|
||||
return false;
|
||||
}
|
||||
reader.readI();
|
||||
|
||||
hz=reader.readF();
|
||||
arpLen=reader.readC();
|
||||
effectDivider=reader.readC();
|
||||
|
||||
patLen=reader.readS();
|
||||
ordersLen=reader.readS();
|
||||
|
||||
hilightA=reader.readC();
|
||||
hilightB=reader.readC();
|
||||
|
||||
virtualTempoN=reader.readS();
|
||||
virtualTempoD=reader.readS();
|
||||
|
||||
speeds.len=reader.readC();
|
||||
for (int i=0; i<16; i++) {
|
||||
speeds.val[i]=reader.readS();
|
||||
}
|
||||
|
||||
name=reader.readString();
|
||||
notes=reader.readString();
|
||||
|
||||
logD("reading orders (%d)...",ordersLen);
|
||||
for (int j=0; j<chans; j++) {
|
||||
for (int k=0; k<ordersLen; k++) {
|
||||
orders.ord[j][k]=reader.readC();
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<chans; i++) {
|
||||
pat[i].effectCols=reader.readC();
|
||||
}
|
||||
|
||||
for (int i=0; i<chans; i++) {
|
||||
unsigned char tempchar=reader.readC();
|
||||
chanShow[i]=tempchar&1;
|
||||
chanShowChanOsc[i]=tempchar&2;
|
||||
}
|
||||
|
||||
for (int i=0; i<chans; i++) {
|
||||
chanCollapse[i]=reader.readC();
|
||||
}
|
||||
|
||||
for (int i=0; i<chans; i++) {
|
||||
chanName[i]=reader.readString();
|
||||
}
|
||||
|
||||
for (int i=0; i<chans; i++) {
|
||||
chanShortName[i]=reader.readString();
|
||||
}
|
||||
|
||||
for (int i=0; i<chans; i++) {
|
||||
chanColor[i]=reader.readI();
|
||||
}
|
||||
} else {
|
||||
if (memcmp(magic,"SONG",4)!=0) {
|
||||
logE("invalid subsong header!");
|
||||
return false;
|
||||
}
|
||||
reader.readI();
|
||||
|
||||
unsigned char oldTimeBase=reader.readC();
|
||||
speeds.len=2;
|
||||
speeds.val[0]=(unsigned char)reader.readC();
|
||||
speeds.val[1]=(unsigned char)reader.readC();
|
||||
arpLen=reader.readC();
|
||||
hz=reader.readF();
|
||||
|
||||
patLen=reader.readS();
|
||||
ordersLen=reader.readS();
|
||||
|
||||
hilightA=reader.readC();
|
||||
hilightB=reader.readC();
|
||||
|
||||
if (version>=96) {
|
||||
virtualTempoN=reader.readS();
|
||||
virtualTempoD=reader.readS();
|
||||
} else {
|
||||
reader.readI();
|
||||
}
|
||||
|
||||
name=reader.readString();
|
||||
notes=reader.readString();
|
||||
|
||||
logD("reading orders (%d)...",ordersLen);
|
||||
for (int j=0; j<chans; j++) {
|
||||
for (int k=0; k<ordersLen; k++) {
|
||||
orders.ord[j][k]=reader.readC();
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<chans; i++) {
|
||||
pat[i].effectCols=reader.readC();
|
||||
}
|
||||
|
||||
for (int i=0; i<chans; i++) {
|
||||
if (version<189) {
|
||||
chanShow[i]=reader.readC();
|
||||
chanShowChanOsc[i]=chanShow[i];
|
||||
} else {
|
||||
unsigned char tempchar=reader.readC();
|
||||
chanShow[i]=tempchar&1;
|
||||
chanShowChanOsc[i]=tempchar&2;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<chans; i++) {
|
||||
chanCollapse[i]=reader.readC();
|
||||
}
|
||||
|
||||
for (int i=0; i<chans; i++) {
|
||||
chanName[i]=reader.readString();
|
||||
}
|
||||
|
||||
for (int i=0; i<chans; i++) {
|
||||
chanShortName[i]=reader.readString();
|
||||
}
|
||||
|
||||
if (version>=139) {
|
||||
speeds.len=reader.readC();
|
||||
for (int i=0; i<16; i++) {
|
||||
speeds.val[i]=(unsigned char)reader.readC();
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<16; i++) {
|
||||
speeds.val[i]*=(oldTimeBase+1);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DivSubSong::putData(SafeWriter* w, int chans) {
|
||||
size_t blockStartSeek, blockEndSeek;
|
||||
w->write("SNG2",4);
|
||||
blockStartSeek=w->tell();
|
||||
w->writeI(0);
|
||||
|
||||
w->writeF(hz);
|
||||
w->writeC(arpLen);
|
||||
w->writeC(effectDivider);
|
||||
w->writeS(patLen);
|
||||
w->writeS(ordersLen);
|
||||
w->writeC(hilightA);
|
||||
w->writeC(hilightB);
|
||||
w->writeS(virtualTempoN);
|
||||
w->writeS(virtualTempoD);
|
||||
|
||||
// speeds
|
||||
w->writeC(speeds.len);
|
||||
for (int i=0; i<16; i++) {
|
||||
w->writeS(speeds.val[i]);
|
||||
}
|
||||
|
||||
w->writeString(name,false);
|
||||
w->writeString(notes,false);
|
||||
|
||||
for (int i=0; i<chans; i++) {
|
||||
for (int j=0; j<ordersLen; j++) {
|
||||
w->writeC(orders.ord[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<chans; i++) {
|
||||
w->writeC(pat[i].effectCols);
|
||||
}
|
||||
|
||||
for (int i=0; i<chans; i++) {
|
||||
w->writeC(
|
||||
(chanShow[i]?1:0)|
|
||||
(chanShowChanOsc[i]?2:0)
|
||||
);
|
||||
}
|
||||
|
||||
for (int i=0; i<chans; i++) {
|
||||
w->writeC(chanCollapse[i]);
|
||||
}
|
||||
|
||||
for (int i=0; i<chans; i++) {
|
||||
w->writeString(chanName[i],false);
|
||||
}
|
||||
|
||||
for (int i=0; i<chans; i++) {
|
||||
w->writeString(chanShortName[i],false);
|
||||
}
|
||||
|
||||
for (int i=0; i<chans; i++) {
|
||||
w->writeI(chanColor[i]);
|
||||
}
|
||||
|
||||
blockEndSeek=w->tell();
|
||||
w->seek(blockStartSeek,SEEK_SET);
|
||||
w->writeI(blockEndSeek-blockStartSeek-4);
|
||||
w->seek(0,SEEK_END);
|
||||
}
|
||||
|
||||
void DivSubSong::clearData() {
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
pat[i].wipePatterns();
|
||||
|
|
@ -574,7 +785,7 @@ void DivSubSong::makePatUnique() {
|
|||
}
|
||||
}
|
||||
|
||||
void DivSong::findSubSongs(int chans) {
|
||||
void DivSong::findSubSongs() {
|
||||
std::vector<DivSubSong*> newSubSongs;
|
||||
for (DivSubSong* i: subsong) {
|
||||
std::vector<int> subSongStart;
|
||||
|
|
@ -584,7 +795,7 @@ void DivSong::findSubSongs(int chans) {
|
|||
// find possible subsongs
|
||||
logD("finding subsongs...");
|
||||
while (++curStart<i->ordersLen) {
|
||||
i->calcTimestamps(chans,grooves,jumpTreatment,ignoreJumpAtEnd,brokenSpeedSel,delayBehavior,curStart);
|
||||
i->calcTimestamps(chans,grooves,compatFlags.jumpTreatment,compatFlags.ignoreJumpAtEnd,compatFlags.brokenSpeedSel,compatFlags.delayBehavior,curStart);
|
||||
if (!i->ts.isLoopable) break;
|
||||
|
||||
// make sure we don't pick the same range twice
|
||||
|
|
@ -620,7 +831,7 @@ void DivSong::findSubSongs(int chans) {
|
|||
theCopy->notes=i->notes;
|
||||
theCopy->hilightA=i->hilightA;
|
||||
theCopy->hilightB=i->hilightB;
|
||||
theCopy->timeBase=i->timeBase;
|
||||
theCopy->effectDivider=i->effectDivider;
|
||||
theCopy->arpLen=i->arpLen;
|
||||
theCopy->speeds=i->speeds;
|
||||
theCopy->virtualTempoN=i->virtualTempoN;
|
||||
|
|
@ -642,6 +853,7 @@ void DivSong::findSubSongs(int chans) {
|
|||
memcpy(theCopy->chanShow,i->chanShow,DIV_MAX_CHANS*sizeof(bool));
|
||||
memcpy(theCopy->chanShowChanOsc,i->chanShowChanOsc,DIV_MAX_CHANS*sizeof(bool));
|
||||
memcpy(theCopy->chanCollapse,i->chanCollapse,DIV_MAX_CHANS);
|
||||
memcpy(theCopy->chanColor,i->chanColor,DIV_MAX_CHANS*sizeof(unsigned int));
|
||||
|
||||
for (int k=0; k<DIV_MAX_CHANS; k++) {
|
||||
theCopy->chanName[k]=i->chanName[k];
|
||||
|
|
@ -689,7 +901,69 @@ void DivSong::findSubSongs(int chans) {
|
|||
for (DivSubSong* i: newSubSongs) {
|
||||
subsong.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
void DivSong::initDefaultSystemChans() {
|
||||
for (int i=0; i<systemLen; i++) {
|
||||
const DivSysDef* sysDef=DivEngine::getSystemDef(system[i]);
|
||||
if (sysDef==NULL) {
|
||||
systemChans[i]=0;
|
||||
} else {
|
||||
systemChans[i]=sysDef->channels;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DivSong::recalcChans() {
|
||||
logV("DivSong: recalcChans() called");
|
||||
|
||||
bool isInsTypePossible[DIV_INS_MAX];
|
||||
chans=0;
|
||||
int chanIndex=0;
|
||||
memset(isInsTypePossible,0,DIV_INS_MAX*sizeof(bool));
|
||||
for (int i=0; i<systemLen; i++) {
|
||||
const DivSysDef* sysDef=DivEngine::getSystemDef(system[i]);
|
||||
int chanCount=systemChans[i];
|
||||
int firstChan=chans;
|
||||
chans+=chanCount;
|
||||
for (int j=0; j<chanCount; j++) {
|
||||
sysOfChan[chanIndex]=system[i];
|
||||
dispatchOfChan[chanIndex]=i;
|
||||
if (sysDef==NULL) {
|
||||
dispatchChanOfChan[chanIndex]=-1;
|
||||
} else if (j<sysDef->maxChans) {
|
||||
dispatchChanOfChan[chanIndex]=j;
|
||||
} else {
|
||||
dispatchChanOfChan[chanIndex]=-1;
|
||||
}
|
||||
dispatchFirstChan[chanIndex]=firstChan;
|
||||
if (sysDef!=NULL) {
|
||||
chanDef[chanIndex]=sysDef->getChanDef(j);
|
||||
if (chanDef[chanIndex].insType[0]!=DIV_INS_NULL) {
|
||||
isInsTypePossible[chanDef[chanIndex].insType[0]]=true;
|
||||
}
|
||||
|
||||
if (chanDef[chanIndex].insType[1]!=DIV_INS_NULL) {
|
||||
isInsTypePossible[chanDef[chanIndex].insType[1]]=true;
|
||||
}
|
||||
} else {
|
||||
chanDef[chanIndex]=DivChanDef();
|
||||
}
|
||||
|
||||
chanIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
possibleInsTypes.clear();
|
||||
for (int i=0; i<DIV_INS_MAX; i++) {
|
||||
if (isInsTypePossible[i]) possibleInsTypes.push_back((DivInstrumentType)i);
|
||||
}
|
||||
|
||||
checkAssetDir(insDir,ins.size());
|
||||
checkAssetDir(waveDir,wave.size());
|
||||
checkAssetDir(sampleDir,sample.size());
|
||||
|
||||
logV("%d channels (%d chips)",chans,systemLen);
|
||||
}
|
||||
|
||||
void DivSong::clearSongData() {
|
||||
|
|
@ -749,4 +1023,201 @@ void DivSong::unload() {
|
|||
delete i;
|
||||
}
|
||||
subsong.clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool DivGroovePattern::readData(SafeReader& reader) {
|
||||
unsigned char magic[4];
|
||||
|
||||
reader.read(magic,4);
|
||||
|
||||
if (memcmp(magic,"GROV",4)!=0) {
|
||||
logE("invalid groove header!");
|
||||
return false;
|
||||
}
|
||||
reader.readI();
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DivGroovePattern::putData(SafeWriter* w) {
|
||||
size_t blockStartSeek, blockEndSeek;
|
||||
w->write("GROV",4);
|
||||
blockStartSeek=w->tell();
|
||||
w->writeI(0);
|
||||
|
||||
w->writeC(len);
|
||||
for (int i=0; i<16; i++) {
|
||||
w->writeS(val[i]);
|
||||
}
|
||||
|
||||
blockEndSeek=w->tell();
|
||||
w->seek(blockStartSeek,SEEK_SET);
|
||||
w->writeI(blockEndSeek-blockStartSeek-4);
|
||||
w->seek(0,SEEK_END);
|
||||
}
|
||||
|
||||
void DivCompatFlags::setDefaults() {
|
||||
limitSlides=false;
|
||||
linearPitch=1;
|
||||
pitchSlideSpeed=4;
|
||||
loopModality=2;
|
||||
delayBehavior=2;
|
||||
jumpTreatment=0;
|
||||
properNoiseLayout=true;
|
||||
waveDutyIsVol=false;
|
||||
resetMacroOnPorta=false;
|
||||
legacyVolumeSlides=false;
|
||||
compatibleArpeggio=false;
|
||||
noteOffResetsSlides=true;
|
||||
targetResetsSlides=true;
|
||||
arpNonPorta=false;
|
||||
algMacroBehavior=false;
|
||||
brokenShortcutSlides=false;
|
||||
ignoreDuplicateSlides=false;
|
||||
stopPortaOnNoteOff=false;
|
||||
continuousVibrato=false;
|
||||
brokenDACMode=false;
|
||||
oneTickCut=false;
|
||||
newInsTriggersInPorta=true;
|
||||
arp0Reset=true;
|
||||
brokenSpeedSel=false;
|
||||
noSlidesOnFirstTick=false;
|
||||
rowResetsArpPos=false;
|
||||
ignoreJumpAtEnd=false;
|
||||
buggyPortaAfterSlide=false;
|
||||
gbInsAffectsEnvelope=true;
|
||||
sharedExtStat=true;
|
||||
ignoreDACModeOutsideIntendedChannel=false;
|
||||
e1e2AlsoTakePriority=false;
|
||||
newSegaPCM=true;
|
||||
fbPortaPause=false;
|
||||
snDutyReset=false;
|
||||
pitchMacroIsLinear=true;
|
||||
oldOctaveBoundary=false;
|
||||
noOPN2Vol=false;
|
||||
newVolumeScaling=true;
|
||||
volMacroLinger=true;
|
||||
brokenOutVol=false;
|
||||
brokenOutVol2=false;
|
||||
e1e2StopOnSameNote=false;
|
||||
brokenPortaArp=false;
|
||||
snNoLowPeriods=false;
|
||||
disableSampleMacro=false;
|
||||
oldArpStrategy=false;
|
||||
brokenPortaLegato=false;
|
||||
brokenFMOff=false;
|
||||
preNoteNoEffect=false;
|
||||
oldDPCM=false;
|
||||
resetArpPhaseOnNewNote=false;
|
||||
ceilVolumeScaling=false;
|
||||
oldAlwaysSetVolume=false;
|
||||
oldSampleOffset=false;
|
||||
oldCenterRate=true;
|
||||
}
|
||||
|
||||
bool DivCompatFlags::areDefaults() {
|
||||
return (*this==defaultFlags);
|
||||
}
|
||||
|
||||
bool DivCompatFlags::readData(SafeReader& reader) {
|
||||
DivConfig c;
|
||||
unsigned char magic[4];
|
||||
|
||||
reader.read(magic,4);
|
||||
if (memcmp(magic,"CFLG",4)!=0) {
|
||||
return false;
|
||||
}
|
||||
reader.readI();
|
||||
|
||||
String data=reader.readString();
|
||||
c.loadFromMemory(data.c_str());
|
||||
|
||||
// TODO: this
|
||||
return true;
|
||||
}
|
||||
|
||||
#define CHECK_AND_STORE_BOOL(_x) \
|
||||
if (_x!=defaultFlags._x) { \
|
||||
c.set(#_x,_x); \
|
||||
}
|
||||
|
||||
#define CHECK_AND_STORE_UNSIGNED_CHAR(_x) \
|
||||
if (_x!=defaultFlags._x) { \
|
||||
c.set(#_x,(int)_x); \
|
||||
}
|
||||
|
||||
void DivCompatFlags::putData(SafeWriter* w) {
|
||||
DivConfig c;
|
||||
size_t blockStartSeek, blockEndSeek;
|
||||
|
||||
CHECK_AND_STORE_BOOL(limitSlides);
|
||||
CHECK_AND_STORE_UNSIGNED_CHAR(linearPitch);
|
||||
CHECK_AND_STORE_UNSIGNED_CHAR(pitchSlideSpeed);
|
||||
CHECK_AND_STORE_UNSIGNED_CHAR(loopModality);
|
||||
CHECK_AND_STORE_UNSIGNED_CHAR(delayBehavior);
|
||||
CHECK_AND_STORE_UNSIGNED_CHAR(jumpTreatment);
|
||||
CHECK_AND_STORE_BOOL(properNoiseLayout);
|
||||
CHECK_AND_STORE_BOOL(waveDutyIsVol);
|
||||
CHECK_AND_STORE_BOOL(resetMacroOnPorta);
|
||||
CHECK_AND_STORE_BOOL(legacyVolumeSlides);
|
||||
CHECK_AND_STORE_BOOL(compatibleArpeggio);
|
||||
CHECK_AND_STORE_BOOL(noteOffResetsSlides);
|
||||
CHECK_AND_STORE_BOOL(targetResetsSlides);
|
||||
CHECK_AND_STORE_BOOL(arpNonPorta);
|
||||
CHECK_AND_STORE_BOOL(algMacroBehavior);
|
||||
CHECK_AND_STORE_BOOL(brokenShortcutSlides);
|
||||
CHECK_AND_STORE_BOOL(ignoreDuplicateSlides);
|
||||
CHECK_AND_STORE_BOOL(stopPortaOnNoteOff);
|
||||
CHECK_AND_STORE_BOOL(continuousVibrato);
|
||||
CHECK_AND_STORE_BOOL(brokenDACMode);
|
||||
CHECK_AND_STORE_BOOL(oneTickCut);
|
||||
CHECK_AND_STORE_BOOL(newInsTriggersInPorta);
|
||||
CHECK_AND_STORE_BOOL(arp0Reset);
|
||||
CHECK_AND_STORE_BOOL(brokenSpeedSel);
|
||||
CHECK_AND_STORE_BOOL(noSlidesOnFirstTick);
|
||||
CHECK_AND_STORE_BOOL(rowResetsArpPos);
|
||||
CHECK_AND_STORE_BOOL(ignoreJumpAtEnd);
|
||||
CHECK_AND_STORE_BOOL(buggyPortaAfterSlide);
|
||||
CHECK_AND_STORE_BOOL(gbInsAffectsEnvelope);
|
||||
CHECK_AND_STORE_BOOL(sharedExtStat);
|
||||
CHECK_AND_STORE_BOOL(ignoreDACModeOutsideIntendedChannel);
|
||||
CHECK_AND_STORE_BOOL(e1e2AlsoTakePriority);
|
||||
CHECK_AND_STORE_BOOL(newSegaPCM);
|
||||
CHECK_AND_STORE_BOOL(fbPortaPause);
|
||||
CHECK_AND_STORE_BOOL(snDutyReset);
|
||||
CHECK_AND_STORE_BOOL(pitchMacroIsLinear);
|
||||
CHECK_AND_STORE_BOOL(oldOctaveBoundary);
|
||||
CHECK_AND_STORE_BOOL(noOPN2Vol);
|
||||
CHECK_AND_STORE_BOOL(newVolumeScaling);
|
||||
CHECK_AND_STORE_BOOL(volMacroLinger);
|
||||
CHECK_AND_STORE_BOOL(brokenOutVol);
|
||||
CHECK_AND_STORE_BOOL(brokenOutVol2);
|
||||
CHECK_AND_STORE_BOOL(e1e2StopOnSameNote);
|
||||
CHECK_AND_STORE_BOOL(brokenPortaArp);
|
||||
CHECK_AND_STORE_BOOL(snNoLowPeriods);
|
||||
CHECK_AND_STORE_BOOL(disableSampleMacro);
|
||||
CHECK_AND_STORE_BOOL(oldArpStrategy);
|
||||
CHECK_AND_STORE_BOOL(brokenPortaLegato);
|
||||
CHECK_AND_STORE_BOOL(brokenFMOff);
|
||||
CHECK_AND_STORE_BOOL(preNoteNoEffect);
|
||||
CHECK_AND_STORE_BOOL(oldDPCM);
|
||||
CHECK_AND_STORE_BOOL(resetArpPhaseOnNewNote);
|
||||
CHECK_AND_STORE_BOOL(ceilVolumeScaling);
|
||||
CHECK_AND_STORE_BOOL(oldAlwaysSetVolume);
|
||||
CHECK_AND_STORE_BOOL(oldSampleOffset);
|
||||
CHECK_AND_STORE_BOOL(oldCenterRate);
|
||||
|
||||
String data=c.toString();
|
||||
w->write("CFLG",4);
|
||||
blockStartSeek=w->tell();
|
||||
w->writeI(0);
|
||||
|
||||
w->writeString(data,false);
|
||||
|
||||
blockEndSeek=w->tell();
|
||||
w->seek(blockStartSeek,SEEK_SET);
|
||||
w->writeI(blockEndSeek-blockStartSeek-4);
|
||||
w->seek(0,SEEK_END);
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue