mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-30 08:23:01 +00:00
Merge branch 'master' of https://github.com/tildearrow/furnace into es5506_alt
* 'master' of https://github.com/tildearrow/furnace: (77 commits) GUI: use pattern font for input latch GUI: partially implement note input latch UI GUI: transpose value does not transpose effect ID GUI: prepare for note input latch UI GUI: min ins selector width fix GUI: separate operation masks GUI: add missing FDS preset GUI: prepare for separate operation mask GUI: "none" instrument should not remove inscolumn GUI: fix ins 0 being inserted on blank song GUI: add a "none" option to instrument list update to-do list GUI: add "absorb" instrument input mode use good default instrument when adding ins better default instrument for OPL/OPLL GUI: fix selection being visible in dummy row area Further fix looped sample preview GUI: fix about screen in power saving mode VRC6: saw volume 63 GUI: add an effect list window ... # Conflicts: # src/engine/platform/amiga.cpp # src/engine/vgmOps.cpp # src/gui/dataList.cpp # src/gui/guiConst.cpp # src/gui/insEdit.cpp # src/gui/sampleEdit.cpp
This commit is contained in:
commit
49a41ff862
116 changed files with 2535 additions and 993 deletions
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
@ -187,6 +187,8 @@ jobs:
|
|||
export USE_WAE=ON
|
||||
export CMAKE_EXTRA_ARGS=()
|
||||
if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then
|
||||
# 1. Go to hell
|
||||
export USE_WAE=OFF
|
||||
CMAKE_EXTRA_ARGS+=('-DCMAKE_GENERATOR_PLATFORM=${{ steps.windows-identify.outputs.msvc-target }}')
|
||||
|
||||
# Force static linking
|
||||
|
|
|
@ -401,6 +401,7 @@ src/gui/debugWindow.cpp
|
|||
src/gui/doAction.cpp
|
||||
src/gui/editing.cpp
|
||||
src/gui/editControls.cpp
|
||||
src/gui/effectList.cpp
|
||||
src/gui/insEdit.cpp
|
||||
src/gui/log.cpp
|
||||
src/gui/mixer.cpp
|
||||
|
|
|
@ -11,6 +11,8 @@ this is a multi-system chiptune tracker.
|
|||
|
||||
check out the [Releases](https://github.com/tildearrow/furnace/releases) page. available for Windows, macOS and Linux (AppImage).
|
||||
|
||||
[see here](https://nightly.link/tildearrow/furnace/workflows/build/master) for unstable developer builds.
|
||||
|
||||
## features
|
||||
|
||||
- supports the following systems:
|
||||
|
@ -64,6 +66,8 @@ some people have provided packages for Unix/Unix-like distributions. here's a li
|
|||
|
||||
[![Build furnace](https://github.com/tildearrow/furnace/actions/workflows/build.yml/badge.svg)](https://github.com/tildearrow/furnace/actions/workflows/build.yml)
|
||||
|
||||
if you can't download these artifacts (because GitHub requires you to be logged in), [go here](https://nightly.link/tildearrow/furnace/workflows/build/master) instead.
|
||||
|
||||
**NOTE: do not download the project's source as a .zip or .tar.gz as these do not include the project's submodules which are necessary to proceed with building. please instead use Git as shown below.**
|
||||
|
||||
## dependencies
|
||||
|
|
8
TODO.md
8
TODO.md
|
@ -9,7 +9,10 @@
|
|||
# to-do for 0.6pre1
|
||||
|
||||
- panning macro
|
||||
- QSound?
|
||||
- pitch macro
|
||||
- relative mode
|
||||
- test
|
||||
- piano/input pad
|
||||
- note input via piano
|
||||
- input pad
|
||||
|
@ -26,21 +29,17 @@
|
|||
- ability to customize startup system
|
||||
- store system presets in new file
|
||||
- Game Boy envelope macro/sequence
|
||||
- Game Boy envelope view
|
||||
- option to display chip names instead of "multi-system" on title bar
|
||||
- rewrite the system name detection function anyway
|
||||
- add nightly.link
|
||||
- scroll instrument/wave/sample list when selecting item
|
||||
- "absorb" mode for instrument input - when this happens, current instrument is set to the input value
|
||||
- unified data view
|
||||
- separate "transpose note" and "transpose value" - see next point
|
||||
- volume commands should work on Game Boy
|
||||
- macro editor menu
|
||||
- refactor sysDef.cpp
|
||||
- add another FM editor layout
|
||||
- try to find out why does VSlider not accept keyboard input
|
||||
- finish lock layout
|
||||
- note input latch! and separate edit masks
|
||||
- if macros have release, note off should release them
|
||||
- add "don't scroll on cursor movement" option
|
||||
- add ability to select entire row when clicking on row number
|
||||
|
@ -51,3 +50,4 @@
|
|||
- settings: OK/Cancel buttons should be always visible
|
||||
- Apply button in settings
|
||||
- better FM chip names (number and codename)
|
||||
- find and replace
|
||||
|
|
|
@ -274,6 +274,19 @@ size | description
|
|||
|
||||
# instrument
|
||||
|
||||
notes:
|
||||
|
||||
- the entire instrument is stored, regardless of instrument type.
|
||||
- the macro range varies depending on the instrument type.
|
||||
- "macro open" indicates whether the macro is collapsed or not in the instrument editor.
|
||||
- FM operator order is:
|
||||
- 1/3/2/4 (internal order) for OPN, OPM, OPZ and OPL 4-op
|
||||
- 1/2/?/? (? = unused) for OPL 2-op and OPLL
|
||||
- meaning of extended macros varies depending on instrument type.
|
||||
- meaning of panning macros varies depending on instrument type:
|
||||
- for hard-panned chips (e.g. FM and Game Boy): left panning is 2-bit panning macro (left/right)
|
||||
- otherwise both left and right panning macros are used
|
||||
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
|
@ -282,17 +295,39 @@ size | description
|
|||
2 | format version (see header)
|
||||
1 | instrument type
|
||||
| - 0: standard
|
||||
| - 1: FM
|
||||
| - 1: FM (OPM/OPN)
|
||||
| - 2: Game Boy
|
||||
| - 3: C64
|
||||
| - 4: Amiga/sample
|
||||
| - 5: PC Engine
|
||||
| - 6: AY-3-8910
|
||||
| - 7: AY8930
|
||||
| - 8: TIA
|
||||
| - 9: SAA1099
|
||||
| - 10: VIC
|
||||
| - 11: PET
|
||||
| - 12: VRC6
|
||||
| - 13: OPLL
|
||||
| - 14: OPL
|
||||
| - 15: FDS
|
||||
| - 16: Virtual Boy
|
||||
| - 17: Namco 163
|
||||
| - 18: SCC
|
||||
| - 19: OPZ
|
||||
| - 20: POKEY
|
||||
| - 21: PC Speaker
|
||||
| - 22: WonderSwan
|
||||
| - 23: Lynx
|
||||
| - 24: VERA
|
||||
| - 25: X1-010
|
||||
| - 26: VRC6 (saw)
|
||||
1 | reserved
|
||||
STR | instrument name
|
||||
--- | **FM instrument data**
|
||||
1 | alg
|
||||
1 | alg (SUS on OPLL)
|
||||
1 | feedback
|
||||
1 | fms
|
||||
1 | ams
|
||||
1 | fms (DC on OPLL)
|
||||
1 | ams (DM on OPLL)
|
||||
1 | operator count
|
||||
| - this is either 2 or 4, and is ignored on non-OPL systems.
|
||||
| - always read 4 ops regardless of this value.
|
||||
|
@ -314,10 +349,12 @@ size | description
|
|||
1 | dt
|
||||
1 | d2r
|
||||
1 | ssgEnv
|
||||
1 | dam
|
||||
1 | dvb
|
||||
1 | egt
|
||||
1 | ksl
|
||||
| - bit 4: on (EG-S on OPLL)
|
||||
| - bit 0-3: envelope type
|
||||
1 | dam (for YMU759 compat; REV on OPZ)
|
||||
1 | dvb (for YMU759 compat; FINE on OPZ)
|
||||
1 | egt (for YMU759 compat; FixedFreq on OPZ)
|
||||
1 | ksl (EGShift on OPZ)
|
||||
1 | sus
|
||||
1 | vib
|
||||
1 | ws
|
||||
|
@ -690,15 +727,18 @@ size | description
|
|||
| - 10: A#
|
||||
| - 11: B
|
||||
| - 12: C (of next octave)
|
||||
| - this is actually a leftover of the .dmf format.
|
||||
| - 100: note off
|
||||
| - 100: note release
|
||||
| - 100: macro release
|
||||
| - octave
|
||||
| - this is an signed char stored in a short.
|
||||
| - therefore octave value 255 is actually octave -1.
|
||||
| - yep, another leftover of the .dmf format...
|
||||
| - instrument
|
||||
| - volume
|
||||
| - effect and effect data...
|
||||
| - effect and effect data (× effect columns)
|
||||
| - for note/octave, if both values are 0 then it means empty.
|
||||
| - for instrument, volume, effect and effect data, a value of -1 means empty.
|
||||
STR | pattern name (>=51)
|
||||
```
|
||||
|
|
|
@ -146,6 +146,15 @@ enum DivDispatchCmds {
|
|||
DIV_CMD_N163_GLOBAL_WAVE_LOADLEN,
|
||||
DIV_CMD_N163_GLOBAL_WAVE_LOADMODE,
|
||||
|
||||
DIV_CMD_ES5506_FILTER_MODE,
|
||||
DIV_CMD_ES5506_FILTER_K1,
|
||||
DIV_CMD_ES5506_FILTER_K2,
|
||||
DIV_CMD_ES5506_ENVELOPE_COUNT,
|
||||
DIV_CMD_ES5506_ENVELOPE_LVRAMP,
|
||||
DIV_CMD_ES5506_ENVELOPE_RVRAMP,
|
||||
DIV_CMD_ES5506_ENVELOPE_K1RAMP,
|
||||
DIV_CMD_ES5506_ENVELOPE_K2RAMP,
|
||||
|
||||
DIV_ALWAYS_SET_VOLUME,
|
||||
|
||||
DIV_CMD_MAX
|
||||
|
@ -245,8 +254,9 @@ class DivDispatch {
|
|||
|
||||
/**
|
||||
* ticks this dispatch.
|
||||
* @param sysTick whether the engine has ticked (if not then this may be a sub-tick used in low-latency mode).
|
||||
*/
|
||||
virtual void tick();
|
||||
virtual void tick(bool sysTick=true);
|
||||
|
||||
/**
|
||||
* get the state of a channel.
|
||||
|
|
|
@ -41,7 +41,7 @@ void process(void* u, float** in, float** out, int inChans, int outChans, unsign
|
|||
((DivEngine*)u)->nextBuf(in,out,inChans,outChans,size);
|
||||
}
|
||||
|
||||
const char* DivEngine::getEffectDesc(unsigned char effect, int chan) {
|
||||
const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNull) {
|
||||
switch (effect) {
|
||||
case 0x00:
|
||||
return "00xy: Arpeggio";
|
||||
|
@ -116,14 +116,13 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan) {
|
|||
default:
|
||||
if ((effect&0xf0)==0x90) {
|
||||
return "9xxx: Set sample offset*256";
|
||||
}
|
||||
else if (chan>=0 && chan<chans) {
|
||||
} else if (chan>=0 && chan<chans) {
|
||||
const char* ret=disCont[dispatchOfChan[chan]].dispatch->getEffectName(effect);
|
||||
if (ret!=NULL) return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return "Invalid effect";
|
||||
return notNull?"Invalid effect":NULL;
|
||||
}
|
||||
|
||||
void DivEngine::walkSong(int& loopOrder, int& loopRow, int& loopEnd) {
|
||||
|
@ -397,7 +396,7 @@ void DivEngine::runExportThread() {
|
|||
if (getChannelType(i)==5) {
|
||||
i++;
|
||||
while (true) {
|
||||
if (++i>=chans) break;
|
||||
if (i>=chans) break;
|
||||
if (getChannelType(i)!=5) break;
|
||||
}
|
||||
i--;
|
||||
|
@ -635,10 +634,10 @@ void DivEngine::renderSamples() {
|
|||
break;
|
||||
}
|
||||
if (memPos+length>=16777216) {
|
||||
memcpy(es5506Mem+memPos,s->data16,16777216-memPos);
|
||||
memcpy(es5506Mem+(memPos/sizeof(short)),s->data16,16777216-memPos);
|
||||
logW("out of ES5506 memory for sample %d!",i);
|
||||
} else {
|
||||
memcpy(es5506Mem+memPos,s->data16,length);
|
||||
memcpy(es5506Mem+(memPos/sizeof(short)),s->data16,length);
|
||||
}
|
||||
s->offES5506=memPos;
|
||||
memPos+=length;
|
||||
|
@ -770,8 +769,20 @@ String DivEngine::getWarnings() {
|
|||
return warnings;
|
||||
}
|
||||
|
||||
DivInstrument* DivEngine::getIns(int index) {
|
||||
if (index<0 || index>=song.insLen) return &song.nullIns;
|
||||
DivInstrument* DivEngine::getIns(int index, DivInstrumentType fallbackType) {
|
||||
if (index<0 || index>=song.insLen) {
|
||||
switch (fallbackType) {
|
||||
case DIV_INS_OPLL:
|
||||
return &song.nullInsOPLL;
|
||||
break;
|
||||
case DIV_INS_OPL:
|
||||
return &song.nullInsOPL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return &song.nullIns;
|
||||
}
|
||||
return song.ins[index];
|
||||
}
|
||||
|
||||
|
@ -884,6 +895,7 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) {
|
|||
}
|
||||
if (!preserveDrift) {
|
||||
ticks=1;
|
||||
subticks=1;
|
||||
}
|
||||
skipping=false;
|
||||
cmdStream.clear();
|
||||
|
@ -1338,8 +1350,19 @@ int DivEngine::addInstrument(int refChan) {
|
|||
BUSY_BEGIN;
|
||||
DivInstrument* ins=new DivInstrument;
|
||||
int insCount=(int)song.ins.size();
|
||||
DivInstrumentType prefType=getPreferInsType(refChan);
|
||||
switch (prefType) {
|
||||
case DIV_INS_OPLL:
|
||||
*ins=song.nullInsOPLL;
|
||||
break;
|
||||
case DIV_INS_OPL:
|
||||
*ins=song.nullInsOPL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ins->name=fmt::sprintf("Instrument %d",insCount);
|
||||
ins->type=getPreferInsType(refChan);
|
||||
ins->type=prefType;
|
||||
saveLock.lock();
|
||||
song.ins.push_back(ins);
|
||||
song.insLen=insCount+1;
|
||||
|
@ -2014,7 +2037,7 @@ void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) {
|
|||
}
|
||||
|
||||
do {
|
||||
if ((ins==-1 || getPreferInsType(finalChan)==getIns(ins)->type) && chan[finalChan].midiNote==-1) {
|
||||
if ((ins<0 || ins>=song.insLen || getChannelType(finalChan)==4 || getPreferInsType(finalChan)==getIns(ins)->type || getIns(ins)->type==DIV_INS_AMIGA) && chan[finalChan].midiNote==-1) {
|
||||
chan[finalChan].midiNote=note;
|
||||
pendingNotes.push(DivNoteEvent(finalChan,ins,note,vol,true));
|
||||
break;
|
||||
|
@ -2040,6 +2063,20 @@ void DivEngine::autoNoteOff(int ch, int note, int vol) {
|
|||
}
|
||||
}
|
||||
|
||||
void DivEngine::autoNoteOffAll() {
|
||||
if (!playing) {
|
||||
reset();
|
||||
freelance=true;
|
||||
playing=true;
|
||||
}
|
||||
for (int i=0; i<chans; i++) {
|
||||
if (chan[i].midiNote!=-1) {
|
||||
pendingNotes.push(DivNoteEvent(i,-1,-1,-1,false));
|
||||
chan[i].midiNote=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DivEngine::setOrder(unsigned char order) {
|
||||
BUSY_BEGIN_SOFT;
|
||||
curOrder=order;
|
||||
|
@ -2281,6 +2318,8 @@ bool DivEngine::initAudioBackend() {
|
|||
if (metroVol<0.0f) metroVol=0.0f;
|
||||
if (metroVol>2.0f) metroVol=2.0f;
|
||||
|
||||
if (lowLatency) logI("using low latency mode.");
|
||||
|
||||
switch (audioEngine) {
|
||||
case DIV_AUDIO_JACK:
|
||||
#ifndef HAVE_JACK
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#ifndef _ENGINE_H
|
||||
#define _ENGINE_H
|
||||
#include "instrument.h"
|
||||
#include "song.h"
|
||||
#include "dispatch.h"
|
||||
#include "dataErrors.h"
|
||||
|
@ -42,8 +43,8 @@
|
|||
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
||||
#define BUSY_END isBusy.unlock(); softLocked=false;
|
||||
|
||||
#define DIV_VERSION "dev83"
|
||||
#define DIV_ENGINE_VERSION 83
|
||||
#define DIV_VERSION "dev84"
|
||||
#define DIV_ENGINE_VERSION 84
|
||||
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
|
@ -273,7 +274,7 @@ class DivEngine {
|
|||
void nextRow();
|
||||
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool isSecond);
|
||||
// returns true if end of song.
|
||||
bool nextTick(bool noAccum=false);
|
||||
bool nextTick(bool noAccum=false, bool inhibitLowLat=false);
|
||||
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
|
||||
bool perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal);
|
||||
void recalcChans();
|
||||
|
@ -289,6 +290,7 @@ class DivEngine {
|
|||
void loadVGI(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
|
||||
void loadS3I(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
|
||||
void loadSBI(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
|
||||
void loadBNK(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
|
||||
void loadOPM(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
|
||||
void loadFF(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
|
||||
|
||||
|
@ -310,7 +312,7 @@ class DivEngine {
|
|||
|
||||
void runExportThread();
|
||||
void nextBuf(float** in, float** out, int inChans, int outChans, unsigned int size);
|
||||
DivInstrument* getIns(int index);
|
||||
DivInstrument* getIns(int index, DivInstrumentType fallbackType=DIV_INS_FM);
|
||||
DivWavetable* getWave(int index);
|
||||
DivSample* getSample(int index);
|
||||
// start fresh
|
||||
|
@ -403,7 +405,7 @@ class DivEngine {
|
|||
int getTotalChannelCount();
|
||||
|
||||
// get effect description
|
||||
const char* getEffectDesc(unsigned char effect, int chan);
|
||||
const char* getEffectDesc(unsigned char effect, int chan, bool notNull=false);
|
||||
|
||||
// get channel type
|
||||
// - 0: FM
|
||||
|
@ -573,6 +575,7 @@ class DivEngine {
|
|||
|
||||
void autoNoteOn(int chan, int ins, int note, int vol=-1);
|
||||
void autoNoteOff(int chan, int note, int vol=-1);
|
||||
void autoNoteOffAll();
|
||||
|
||||
// go to order
|
||||
void setOrder(unsigned char order);
|
||||
|
|
|
@ -990,6 +990,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
ds.ignoreDACModeOutsideIntendedChannel=true;
|
||||
ds.e1e2AlsoTakePriority=false;
|
||||
}
|
||||
if (ds.version<84) {
|
||||
ds.newSegaPCM=false;
|
||||
}
|
||||
ds.isDMF=false;
|
||||
|
||||
reader.readS(); // reserved
|
||||
|
@ -1334,7 +1337,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
reader.readC();
|
||||
reader.readC();
|
||||
}
|
||||
for (int i=0; i<23; i++) {
|
||||
if (ds.version>=84) {
|
||||
ds.newSegaPCM=reader.readC();
|
||||
} else {
|
||||
reader.readC();
|
||||
}
|
||||
for (int i=0; i<22; i++) {
|
||||
reader.readC();
|
||||
}
|
||||
}
|
||||
|
@ -2287,7 +2295,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
w->writeC(song.sharedExtStat);
|
||||
w->writeC(song.ignoreDACModeOutsideIntendedChannel);
|
||||
w->writeC(song.e1e2AlsoTakePriority);
|
||||
for (int i=0; i<23; i++) {
|
||||
w->writeC(song.newSegaPCM);
|
||||
for (int i=0; i<22; i++) {
|
||||
w->writeC(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,10 +30,66 @@ enum DivInsFormats {
|
|||
DIV_INSFORMAT_BTI,
|
||||
DIV_INSFORMAT_S3I,
|
||||
DIV_INSFORMAT_SBI,
|
||||
DIV_INSFORMAT_BNK,
|
||||
DIV_INSFORMAT_OPM,
|
||||
DIV_INSFORMAT_FF,
|
||||
};
|
||||
|
||||
// Patch data structures
|
||||
|
||||
// SBI and some other OPL containers
|
||||
struct sbi_t {
|
||||
uint8_t Mcharacteristics,
|
||||
Ccharacteristics,
|
||||
Mscaling_output,
|
||||
Cscaling_output,
|
||||
Meg_AD,
|
||||
Ceg_AD,
|
||||
Meg_SR,
|
||||
Ceg_SR,
|
||||
Mwave,
|
||||
Cwave,
|
||||
FeedConnect;
|
||||
};
|
||||
|
||||
// Adlib Visual Composer BNK
|
||||
struct bnkop_t {
|
||||
uint8_t ksl,
|
||||
multiple,
|
||||
feedback, // op1 only
|
||||
attack,
|
||||
sustain,
|
||||
eg,
|
||||
decay,
|
||||
releaseRate,
|
||||
totalLevel,
|
||||
am,
|
||||
vib,
|
||||
ksr,
|
||||
con; // op1 only
|
||||
};
|
||||
struct bnktimbre_t {
|
||||
uint8_t mode,
|
||||
percVoice;
|
||||
bnkop_t op[2];
|
||||
uint8_t wave0,
|
||||
wave1;
|
||||
};
|
||||
|
||||
auto readSbiOpData = [](sbi_t& sbi, SafeReader& reader) {
|
||||
sbi.Mcharacteristics = reader.readC();
|
||||
sbi.Ccharacteristics = reader.readC();
|
||||
sbi.Mscaling_output = reader.readC();
|
||||
sbi.Cscaling_output = reader.readC();
|
||||
sbi.Meg_AD = reader.readC();
|
||||
sbi.Ceg_AD = reader.readC();
|
||||
sbi.Meg_SR = reader.readC();
|
||||
sbi.Ceg_SR = reader.readC();
|
||||
sbi.Mwave = reader.readC();
|
||||
sbi.Cwave = reader.readC();
|
||||
sbi.FeedConnect = reader.readC();
|
||||
};
|
||||
|
||||
void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath) {
|
||||
DivInstrument* ins=new DivInstrument;
|
||||
// this is a ridiculous mess
|
||||
|
@ -45,7 +101,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
|
|||
logD(".dmp version %d",version);
|
||||
} catch (EndOfFileException& e) {
|
||||
lastError="premature end of file";
|
||||
logE("premature end of file!");
|
||||
logE("premature end of file");
|
||||
delete ins;
|
||||
return;
|
||||
}
|
||||
|
@ -104,7 +160,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
|
|||
}
|
||||
} catch (EndOfFileException& e) {
|
||||
lastError="premature end of file";
|
||||
logE("premature end of file!");
|
||||
logE("premature end of file");
|
||||
delete ins;
|
||||
return;
|
||||
}
|
||||
|
@ -296,7 +352,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
|
|||
}
|
||||
} catch (EndOfFileException& e) {
|
||||
lastError="premature end of file";
|
||||
logE("premature end of file!");
|
||||
logE("premature end of file");
|
||||
delete ins;
|
||||
return;
|
||||
}
|
||||
|
@ -331,7 +387,7 @@ void DivEngine::loadTFI(SafeReader& reader, std::vector<DivInstrument*>& ret, St
|
|||
}
|
||||
} catch (EndOfFileException& e) {
|
||||
lastError="premature end of file";
|
||||
logE("premature end of file!");
|
||||
logE("premature end of file");
|
||||
delete ins;
|
||||
return;
|
||||
}
|
||||
|
@ -373,7 +429,7 @@ void DivEngine::loadVGI(SafeReader& reader, std::vector<DivInstrument*>& ret, St
|
|||
}
|
||||
} catch (EndOfFileException& e) {
|
||||
lastError="premature end of file";
|
||||
logE("premature end of file!");
|
||||
logE("premature end of file");
|
||||
delete ins;
|
||||
return;
|
||||
}
|
||||
|
@ -390,71 +446,70 @@ void DivEngine::loadS3I(SafeReader& reader, std::vector<DivInstrument*>& ret, St
|
|||
|
||||
if (s3i_type >= 2) {
|
||||
ins->type = DIV_INS_OPL;
|
||||
if (s3i_type > 2 && s3i_type <= 7) {
|
||||
ins->fm.opllPreset = (uint8_t)(1<<4); // Flag as Drum preset.
|
||||
}
|
||||
// skip internal filename - we'll use the long name description
|
||||
reader.seek(12, SEEK_CUR);
|
||||
|
||||
// skip reserved bytes
|
||||
reader.seek(3, SEEK_CUR);
|
||||
|
||||
// 12-byte opl value
|
||||
uint8_t s3i_Mcharacteristics = reader.readC();
|
||||
uint8_t s3i_Ccharacteristics = reader.readC();
|
||||
uint8_t s3i_Mscaling_output = reader.readC();
|
||||
uint8_t s3i_Cscaling_output = reader.readC();
|
||||
uint8_t s3i_Meg_AD = reader.readC();
|
||||
uint8_t s3i_Ceg_AD = reader.readC();
|
||||
uint8_t s3i_Meg_SR = reader.readC();
|
||||
uint8_t s3i_Ceg_SR = reader.readC();
|
||||
uint8_t s3i_Mwave = reader.readC();
|
||||
uint8_t s3i_Cwave = reader.readC();
|
||||
uint8_t s3i_FeedConnect = reader.readC();
|
||||
// 12-byte opl value - identical to SBI format
|
||||
sbi_t s3i;
|
||||
|
||||
readSbiOpData(s3i, reader);
|
||||
|
||||
DivInstrumentFM::Operator& opM = ins->fm.op[0];
|
||||
DivInstrumentFM::Operator& opC = ins->fm.op[1];
|
||||
ins->fm.ops = 2;
|
||||
opM.mult = s3i_Mcharacteristics & 0xF;
|
||||
opM.ksr = ((s3i_Mcharacteristics >> 4) & 0x1);
|
||||
opM.sus = ((s3i_Mcharacteristics >> 5) & 0x1);
|
||||
opM.vib = ((s3i_Mcharacteristics >> 6) & 0x1);
|
||||
opM.am = ((s3i_Mcharacteristics >> 7) & 0x1);
|
||||
opM.tl = s3i_Mscaling_output & 0x3F;
|
||||
opM.ksl = ((s3i_Mscaling_output >> 6) & 0x3);
|
||||
opM.ar = ((s3i_Meg_AD >> 4) & 0xF);
|
||||
opM.dr = (s3i_Meg_AD & 0xF);
|
||||
opM.rr = (s3i_Meg_SR & 0xF);
|
||||
opM.sl = ((s3i_Meg_SR >> 4) & 0xF);
|
||||
opM.ws = s3i_Mwave;
|
||||
opM.mult = s3i.Mcharacteristics & 0xF;
|
||||
opM.ksr = ((s3i.Mcharacteristics >> 4) & 0x1);
|
||||
opM.sus = ((s3i.Mcharacteristics >> 5) & 0x1);
|
||||
opM.vib = ((s3i.Mcharacteristics >> 6) & 0x1);
|
||||
opM.am = ((s3i.Mcharacteristics >> 7) & 0x1);
|
||||
opM.tl = s3i.Mscaling_output & 0x3F;
|
||||
opM.ksl = ((s3i.Mscaling_output >> 6) & 0x3);
|
||||
opM.ar = ((s3i.Meg_AD >> 4) & 0xF);
|
||||
opM.dr = (s3i.Meg_AD & 0xF);
|
||||
opM.rr = (s3i.Meg_SR & 0xF);
|
||||
opM.sl = ((s3i.Meg_SR >> 4) & 0xF);
|
||||
opM.ws = s3i.Mwave;
|
||||
|
||||
ins->fm.alg = (s3i_FeedConnect & 0x1);
|
||||
ins->fm.fb = ((s3i_FeedConnect >> 1) & 0x7);
|
||||
ins->fm.alg = (s3i.FeedConnect & 0x1);
|
||||
ins->fm.fb = ((s3i.FeedConnect >> 1) & 0x7);
|
||||
|
||||
opC.mult = s3i_Ccharacteristics & 0xF;
|
||||
opC.ksr = ((s3i_Ccharacteristics >> 4) & 0x1);
|
||||
opC.sus = ((s3i_Ccharacteristics >> 5) & 0x1);
|
||||
opC.vib = ((s3i_Ccharacteristics >> 6) & 0x1);
|
||||
opC.am = ((s3i_Ccharacteristics >> 7) & 0x1);
|
||||
opC.tl = s3i_Cscaling_output & 0x3F;
|
||||
opC.ksl = ((s3i_Cscaling_output >> 6) & 0x3);
|
||||
opC.ar = ((s3i_Ceg_AD >> 4) & 0xF);
|
||||
opC.dr = (s3i_Ceg_AD & 0xF);
|
||||
opC.rr = (s3i_Ceg_SR & 0xF);
|
||||
opC.sl = ((s3i_Ceg_SR >> 4) & 0xF);
|
||||
opC.ws = s3i_Cwave;
|
||||
opC.mult = s3i.Ccharacteristics & 0xF;
|
||||
opC.ksr = ((s3i.Ccharacteristics >> 4) & 0x1);
|
||||
opC.sus = ((s3i.Ccharacteristics >> 5) & 0x1);
|
||||
opC.vib = ((s3i.Ccharacteristics >> 6) & 0x1);
|
||||
opC.am = ((s3i.Ccharacteristics >> 7) & 0x1);
|
||||
opC.tl = s3i.Cscaling_output & 0x3F;
|
||||
opC.ksl = ((s3i.Cscaling_output >> 6) & 0x3);
|
||||
opC.ar = ((s3i.Ceg_AD >> 4) & 0xF);
|
||||
opC.dr = (s3i.Ceg_AD & 0xF);
|
||||
opC.rr = (s3i.Ceg_SR & 0xF);
|
||||
opC.sl = ((s3i.Ceg_SR >> 4) & 0xF);
|
||||
opC.ws = s3i.Cwave;
|
||||
|
||||
// Skip more stuff we don't need
|
||||
reader.seek(21, SEEK_CUR);
|
||||
} else {
|
||||
lastError = "S3I PCM samples currently not supported.";
|
||||
logE("S3I PCM samples currently not supported.");
|
||||
}
|
||||
ins->name = reader.readString(28);
|
||||
ins->name = (ins->name.length() == 0) ? stripPath : ins->name;
|
||||
|
||||
int s3i_signature = reader.readI();
|
||||
|
||||
if (s3i_signature != 0x49524353) {
|
||||
addWarning("S3I signature invalid.");
|
||||
logW("S3I signature invalid.");
|
||||
};
|
||||
} catch (EndOfFileException& e) {
|
||||
lastError = "premature end of file";
|
||||
logE("premature end of file!");
|
||||
logE("premature end of file");
|
||||
delete ins;
|
||||
return;
|
||||
}
|
||||
|
@ -470,77 +525,69 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector<DivInstrument*>& ret, St
|
|||
|
||||
int sbi_header = reader.readI();
|
||||
// SBI header determines format
|
||||
bool is_2op = (sbi_header == 0x1A494253); // SBI\x1A
|
||||
bool is_2op = (sbi_header == 0x1A494253 || sbi_header == 0x1A504F32); // SBI\x1A or 2OP\x1A
|
||||
bool is_4op = (sbi_header == 0x1A504F34); // 4OP\x1A
|
||||
bool is_6op = (sbi_header == 0x1A504F36); // 6OP\x1A - Freq Monster 801-specific
|
||||
|
||||
// 32-byte null terminated instrument name
|
||||
ins->name = reader.readString(32);
|
||||
String patchName = reader.readString(32);
|
||||
patchName = (patchName.length() == 0) ? stripPath : patchName;
|
||||
|
||||
// 2op SBI
|
||||
uint8_t sbi_Mcharacteristics = reader.readC();
|
||||
uint8_t sbi_Ccharacteristics = reader.readC();
|
||||
uint8_t sbi_Mscaling_output = reader.readC();
|
||||
uint8_t sbi_Cscaling_output = reader.readC();
|
||||
uint8_t sbi_Meg_AD = reader.readC();
|
||||
uint8_t sbi_Ceg_AD = reader.readC();
|
||||
uint8_t sbi_Meg_SR = reader.readC();
|
||||
uint8_t sbi_Ceg_SR = reader.readC();
|
||||
uint8_t sbi_Mwave = reader.readC();
|
||||
uint8_t sbi_Cwave = reader.readC();
|
||||
uint8_t sbi_FeedConnect = reader.readC();
|
||||
auto writeOp = [](sbi_t& sbi, DivInstrumentFM::Operator& opM, DivInstrumentFM::Operator& opC) {
|
||||
opM.mult = sbi.Mcharacteristics & 0xF;
|
||||
opM.ksr = ((sbi.Mcharacteristics >> 4) & 0x1);
|
||||
opM.sus = ((sbi.Mcharacteristics >> 5) & 0x1);
|
||||
opM.vib = ((sbi.Mcharacteristics >> 6) & 0x1);
|
||||
opM.am = ((sbi.Mcharacteristics >> 7) & 0x1);
|
||||
opM.tl = sbi.Mscaling_output & 0x3F;
|
||||
opM.ksl = ((sbi.Mscaling_output >> 6) & 0x3);
|
||||
opM.ar = ((sbi.Meg_AD >> 4) & 0xF);
|
||||
opM.dr = (sbi.Meg_AD & 0xF);
|
||||
opM.rr = (sbi.Meg_SR & 0xF);
|
||||
opM.sl = ((sbi.Meg_SR >> 4) & 0xF);
|
||||
opM.ws = sbi.Mwave;
|
||||
|
||||
// 4op SBI
|
||||
uint8_t sbi_M4characteristics;
|
||||
uint8_t sbi_C4characteristics;
|
||||
uint8_t sbi_M4scaling_output;
|
||||
uint8_t sbi_C4scaling_output;
|
||||
uint8_t sbi_M4eg_AD;
|
||||
uint8_t sbi_C4eg_AD;
|
||||
uint8_t sbi_M4eg_SR;
|
||||
uint8_t sbi_C4eg_SR;
|
||||
uint8_t sbi_M4wave;
|
||||
uint8_t sbi_C4wave;
|
||||
uint8_t sbi_4opConnect;
|
||||
opC.mult = sbi.Ccharacteristics & 0xF;
|
||||
opC.ksr = ((sbi.Ccharacteristics >> 4) & 0x1);
|
||||
opC.sus = ((sbi.Ccharacteristics >> 5) & 0x1);
|
||||
opC.vib = ((sbi.Ccharacteristics >> 6) & 0x1);
|
||||
opC.am = ((sbi.Ccharacteristics >> 7) & 0x1);
|
||||
opC.tl = sbi.Cscaling_output & 0x3F;
|
||||
opC.ksl = ((sbi.Cscaling_output >> 6) & 0x3);
|
||||
opC.ar = ((sbi.Ceg_AD >> 4) & 0xF);
|
||||
opC.dr = (sbi.Ceg_AD & 0xF);
|
||||
opC.rr = (sbi.Ceg_SR & 0xF);
|
||||
opC.sl = ((sbi.Ceg_SR >> 4) & 0xF);
|
||||
opC.ws = sbi.Cwave;
|
||||
};
|
||||
|
||||
sbi_t sbi_op12; // 2op (+6op portion)
|
||||
sbi_t sbi_op34; // 4op
|
||||
|
||||
readSbiOpData(sbi_op12, reader);
|
||||
|
||||
if (is_2op) {
|
||||
DivInstrumentFM::Operator& opM = ins->fm.op[0];
|
||||
DivInstrumentFM::Operator& opC = ins->fm.op[1];
|
||||
ins->fm.ops = 2;
|
||||
opM.mult = sbi_Mcharacteristics & 0xF;
|
||||
opM.ksr = ((sbi_Mcharacteristics >> 4) & 0x1);
|
||||
opM.sus = ((sbi_Mcharacteristics >> 5) & 0x1);
|
||||
opM.vib = ((sbi_Mcharacteristics >> 6) & 0x1);
|
||||
opM.am = ((sbi_Mcharacteristics >> 7) & 0x1);
|
||||
opM.tl = sbi_Mscaling_output & 0x3F;
|
||||
opM.ksl = ((sbi_Mscaling_output >> 6) & 0x3);
|
||||
opM.ar = ((sbi_Meg_AD >> 4) & 0xF);
|
||||
opM.dr = (sbi_Meg_AD & 0xF);
|
||||
opM.rr = (sbi_Meg_SR & 0xF);
|
||||
opM.sl = ((sbi_Meg_SR >> 4) & 0xF);
|
||||
opM.ws = sbi_Mwave;
|
||||
ins->name = patchName;
|
||||
writeOp(sbi_op12, opM, opC);
|
||||
ins->fm.alg = (sbi_op12.FeedConnect & 0x1);
|
||||
ins->fm.fb = ((sbi_op12.FeedConnect >> 1) & 0x7);
|
||||
|
||||
ins->fm.alg = (sbi_FeedConnect & 0x1);
|
||||
ins->fm.fb = ((sbi_FeedConnect >> 1) & 0x7);
|
||||
|
||||
opC.mult = sbi_Ccharacteristics & 0xF;
|
||||
opC.ksr = ((sbi_Ccharacteristics >> 4) & 0x1);
|
||||
opC.sus = ((sbi_Ccharacteristics >> 5) & 0x1);
|
||||
opC.vib = ((sbi_Ccharacteristics >> 6) & 0x1);
|
||||
opC.am = ((sbi_Ccharacteristics >> 7) & 0x1);
|
||||
opC.tl = sbi_Cscaling_output & 0x3F;
|
||||
opC.ksl = ((sbi_Cscaling_output >> 6) & 0x3);
|
||||
opC.ar = ((sbi_Ceg_AD >> 4) & 0xF);
|
||||
opC.dr = (sbi_Ceg_AD & 0xF);
|
||||
opC.rr = (sbi_Ceg_SR & 0xF);
|
||||
opC.sl = ((sbi_Ceg_SR >> 4) & 0xF);
|
||||
opC.ws = sbi_Cwave;
|
||||
|
||||
// Ignore rest of file - rest is 'reserved padding'.
|
||||
reader.seek(0, SEEK_END);
|
||||
// SBTimbre extensions
|
||||
uint8_t perc_voc = reader.readC();
|
||||
if (perc_voc >= 6) {
|
||||
ins->fm.opllPreset = (uint8_t)(1 << 4);
|
||||
}
|
||||
|
||||
if (is_4op || is_6op) {
|
||||
// Ignore rest of file - rest is 'reserved padding'.
|
||||
reader.seek(4, SEEK_CUR);
|
||||
ret.push_back(ins);
|
||||
|
||||
} else if (is_4op || is_6op) {
|
||||
readSbiOpData(sbi_op34, reader);
|
||||
|
||||
// Operator placement is different so need to place in correct registers.
|
||||
// Note: 6op is an unofficial extension of 4op SBIs by Darron Broad (Freq Monster 801).
|
||||
// We'll only use the 4op portion here for pure OPL3.
|
||||
|
@ -549,87 +596,144 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector<DivInstrument*>& ret, St
|
|||
DivInstrumentFM::Operator& opM4 = ins->fm.op[1];
|
||||
DivInstrumentFM::Operator& opC4 = ins->fm.op[3];
|
||||
ins->fm.ops = 4;
|
||||
ins->name = patchName;
|
||||
ins->fm.alg = (sbi_op12.FeedConnect & 0x1) | ((sbi_op34.FeedConnect & 0x1) << 1);
|
||||
ins->fm.fb = ((sbi_op34.FeedConnect >> 1) & 0x7);
|
||||
writeOp(sbi_op12, opM, opC);
|
||||
writeOp(sbi_op34, opM4, opC4);
|
||||
|
||||
sbi_M4characteristics = reader.readC();
|
||||
sbi_C4characteristics = reader.readC();
|
||||
sbi_M4scaling_output = reader.readC();
|
||||
sbi_C4scaling_output = reader.readC();
|
||||
sbi_M4eg_AD = reader.readC();
|
||||
sbi_C4eg_AD = reader.readC();
|
||||
sbi_M4eg_SR = reader.readC();
|
||||
sbi_C4eg_SR = reader.readC();
|
||||
sbi_M4wave = reader.readC();
|
||||
sbi_C4wave = reader.readC();
|
||||
sbi_4opConnect = reader.readC();
|
||||
if (is_6op) {
|
||||
// Freq Monster 801 6op SBIs use a 4+2op layout
|
||||
// Save the 4op portion before reading the 2op part
|
||||
ins->name = fmt::format("{0} (4op)", ins->name);
|
||||
ret.push_back(ins);
|
||||
|
||||
ins->fm.alg = (sbi_FeedConnect & 0x1) | ((sbi_4opConnect & 0x1) << 1);
|
||||
ins->fm.fb = ((sbi_FeedConnect >> 1) & 0x7);
|
||||
readSbiOpData(sbi_op12, reader);
|
||||
|
||||
opM.mult = sbi_Mcharacteristics & 0xF;
|
||||
opM.ksr = ((sbi_Mcharacteristics >> 4) & 0x1);
|
||||
opM.sus = ((sbi_Mcharacteristics >> 5) & 0x1);
|
||||
opM.vib = ((sbi_Mcharacteristics >> 6) & 0x1);
|
||||
opM.am = ((sbi_Mcharacteristics >> 7) & 0x1);
|
||||
opM.tl = sbi_Mscaling_output & 0x3F;
|
||||
opM.ksl = ((sbi_Mscaling_output >> 6) & 0x3);
|
||||
opM.ar = ((sbi_Meg_AD >> 4) & 0xF);
|
||||
opM.dr = (sbi_Meg_AD & 0xF);
|
||||
opM.rr = (sbi_Meg_SR & 0xF);
|
||||
opM.sl = ((sbi_Meg_SR >> 4) & 0xF);
|
||||
opM.ws = sbi_Mwave;
|
||||
|
||||
opC.mult = sbi_Ccharacteristics & 0xF;
|
||||
opC.ksr = ((sbi_Ccharacteristics >> 4) & 0x1);
|
||||
opC.sus = ((sbi_Ccharacteristics >> 5) & 0x1);
|
||||
opC.vib = ((sbi_Ccharacteristics >> 6) & 0x1);
|
||||
opC.am = ((sbi_Ccharacteristics >> 7) & 0x1);
|
||||
opC.tl = sbi_Cscaling_output & 0x3F;
|
||||
opC.ksl = ((sbi_Cscaling_output >> 6) & 0x3);
|
||||
opC.ar = ((sbi_Ceg_AD >> 4) & 0xF);
|
||||
opC.dr = (sbi_Ceg_AD & 0xF);
|
||||
opC.rr = (sbi_Ceg_SR & 0xF);
|
||||
opC.sl = ((sbi_Ceg_SR >> 4) & 0xF);
|
||||
opC.ws = sbi_Cwave;
|
||||
|
||||
opM4.mult = sbi_M4characteristics & 0xF;
|
||||
opM4.ksr = ((sbi_M4characteristics >> 4) & 0x1);
|
||||
opM4.sus = ((sbi_M4characteristics >> 5) & 0x1);
|
||||
opM4.vib = ((sbi_M4characteristics >> 6) & 0x1);
|
||||
opM4.am = ((sbi_M4characteristics >> 7) & 0x1);
|
||||
opM4.tl = sbi_M4scaling_output & 0x3F;
|
||||
opM4.ksl = ((sbi_M4scaling_output >> 6) & 0x3);
|
||||
opM4.ar = ((sbi_M4eg_AD >> 4) & 0xF);
|
||||
opM4.dr = (sbi_M4eg_AD & 0xF);
|
||||
opM4.rr = (sbi_M4eg_SR & 0xF);
|
||||
opM4.sl = ((sbi_M4eg_SR >> 4) & 0xF);
|
||||
opM4.ws = sbi_M4wave;
|
||||
|
||||
opC4.mult = sbi_C4characteristics & 0xF;
|
||||
opC4.ksr = ((sbi_C4characteristics >> 4) & 0x1);
|
||||
opC4.sus = ((sbi_C4characteristics >> 5) & 0x1);
|
||||
opC4.vib = ((sbi_C4characteristics >> 6) & 0x1);
|
||||
opC4.am = ((sbi_C4characteristics >> 7) & 0x1);
|
||||
opC4.tl = sbi_C4scaling_output & 0x3F;
|
||||
opC4.ksl = ((sbi_C4scaling_output >> 6) & 0x3);
|
||||
opC4.ar = ((sbi_C4eg_AD >> 4) & 0xF);
|
||||
opC4.dr = (sbi_C4eg_AD & 0xF);
|
||||
opC4.rr = (sbi_C4eg_SR & 0xF);
|
||||
opC4.sl = ((sbi_C4eg_SR >> 4) & 0xF);
|
||||
opC4.ws = sbi_C4wave;
|
||||
ins = new DivInstrument;
|
||||
DivInstrumentFM::Operator& opM6 = ins->fm.op[0];
|
||||
DivInstrumentFM::Operator& opC6 = ins->fm.op[1];
|
||||
ins->type = DIV_INS_OPL;
|
||||
ins->fm.ops = 2;
|
||||
ins->name = fmt::format("{0} (2op)", patchName);
|
||||
writeOp(sbi_op12, opM6, opC6);
|
||||
ins->fm.alg = (sbi_op12.FeedConnect & 0x1);
|
||||
ins->fm.fb = ((sbi_op12.FeedConnect >> 1) & 0x7);
|
||||
}
|
||||
|
||||
// Ignore rest of file once we've read in all we need.
|
||||
// Note: Freq Monster 801 adds a ton of other additional fields irrelevant to chip registers.
|
||||
// If instrument transpose is ever supported, we can read it in maybe?
|
||||
reader.seek(0, SEEK_END);
|
||||
ret.push_back(ins);
|
||||
}
|
||||
|
||||
} catch (EndOfFileException& e) {
|
||||
lastError = "premature end of file";
|
||||
logE("premature end of file!");
|
||||
logE("premature end of file");
|
||||
delete ins;
|
||||
return;
|
||||
}
|
||||
}
|
||||
void DivEngine::loadBNK(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath) {
|
||||
std::vector<DivInstrument*> insList;
|
||||
std::vector<String*> instNames;
|
||||
reader.seek(0, SEEK_SET);
|
||||
|
||||
// First distinguish between GEMS BNK and Adlib BNK
|
||||
uint64_t header = reader.readL();
|
||||
bool is_adlib = ((header>>8) == 0x2d42494c444100L);
|
||||
bool is_failed = false;
|
||||
int readCount = 0;
|
||||
|
||||
if (is_adlib) {
|
||||
try {
|
||||
reader.seek(0x0c, SEEK_SET);
|
||||
uint32_t name_offset = reader.readI();
|
||||
reader.seek(0x10, SEEK_SET);
|
||||
uint32_t data_offset = reader.readI();
|
||||
|
||||
// Seek to BNK patch names
|
||||
reader.seek(name_offset, SEEK_SET);
|
||||
while (reader.tell() < data_offset) {
|
||||
reader.seek(3, SEEK_CUR);
|
||||
instNames.push_back(new String(reader.readString(9)));
|
||||
++readCount;
|
||||
}
|
||||
|
||||
ret.push_back(ins);
|
||||
// Seek to BNK data
|
||||
reader.seek(data_offset, SEEK_SET);
|
||||
|
||||
// Read until EOF
|
||||
for (int i = 0; i < readCount; ++i) {
|
||||
bnktimbre_t timbre;
|
||||
insList.push_back(new DivInstrument);
|
||||
auto& ins = insList[i];
|
||||
|
||||
ins->type = DIV_INS_OPL;
|
||||
|
||||
timbre.mode = reader.readC();
|
||||
timbre.percVoice = reader.readC();
|
||||
if (timbre.mode == 1) {
|
||||
ins->fm.opllPreset = (uint8_t)(1<<4);
|
||||
}
|
||||
ins->fm.op[0].ksl = reader.readC();
|
||||
ins->fm.op[0].mult = reader.readC();
|
||||
ins->fm.fb = reader.readC();
|
||||
ins->fm.op[0].ar = reader.readC();
|
||||
ins->fm.op[0].sl = reader.readC();
|
||||
ins->fm.op[0].sus = (reader.readC() != 0) ? 1 : 0;
|
||||
ins->fm.op[0].dr = reader.readC();
|
||||
ins->fm.op[0].rr = reader.readC();
|
||||
ins->fm.op[0].tl = reader.readC();
|
||||
ins->fm.op[0].am = reader.readC();
|
||||
ins->fm.op[0].vib = reader.readC();
|
||||
ins->fm.op[0].ksr = reader.readC();
|
||||
ins->fm.alg = (reader.readC() == 0) ? 1 : 0;
|
||||
|
||||
ins->fm.op[1].ksl = reader.readC();
|
||||
ins->fm.op[1].mult = reader.readC();
|
||||
reader.readC(); // skip
|
||||
ins->fm.op[1].ar = reader.readC();
|
||||
ins->fm.op[1].sl = reader.readC();
|
||||
ins->fm.op[1].sus = (reader.readC() != 0) ? 1 : 0;
|
||||
ins->fm.op[1].dr = reader.readC();
|
||||
ins->fm.op[1].rr = reader.readC();
|
||||
ins->fm.op[1].tl = reader.readC();
|
||||
ins->fm.op[1].am = reader.readC();
|
||||
ins->fm.op[1].vib = reader.readC();
|
||||
ins->fm.op[1].ksr = reader.readC();
|
||||
reader.readC(); // skip
|
||||
|
||||
ins->fm.op[0].ws = reader.readC();
|
||||
ins->fm.op[1].ws = reader.readC();
|
||||
ins->name = instNames[i]->length() > 0 ? (*instNames[i]) : fmt::format("{0}[{1}]", stripPath, i);
|
||||
}
|
||||
reader.seek(0, SEEK_END);
|
||||
|
||||
} catch (EndOfFileException& e) {
|
||||
lastError = "premature end of file";
|
||||
logE("premature end of file");
|
||||
for (int i = readCount; i >= 0; --i) {
|
||||
delete insList[i];
|
||||
}
|
||||
is_failed = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
// assume GEMS BNK for now.
|
||||
lastError = "GEMS BNK currently not supported.";
|
||||
logE("GEMS BNK currently not supported.");
|
||||
}
|
||||
|
||||
if (!is_failed) {
|
||||
for (int i = 0; i < readCount; ++i) {
|
||||
ret.push_back(insList[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& name : instNames) {
|
||||
delete name;
|
||||
}
|
||||
}
|
||||
|
||||
void DivEngine::loadFF(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath) {
|
||||
|
@ -693,7 +797,7 @@ void DivEngine::loadFF(SafeReader& reader, std::vector<DivInstrument*>& ret, Str
|
|||
}
|
||||
} catch (EndOfFileException& e) {
|
||||
lastError = "premature end of file";
|
||||
logE("premature end of file!\n");
|
||||
logE("premature end of file");
|
||||
for (int i = readCount; i >= 0; --i) {
|
||||
delete insList[i];
|
||||
}
|
||||
|
@ -714,7 +818,7 @@ void DivEngine::loadOPM(SafeReader& reader, std::vector<DivInstrument*>& ret, St
|
|||
|
||||
} catch (EndOfFileException& e) {
|
||||
lastError="premature end of file";
|
||||
logE("premature end of file!");
|
||||
logE("premature end of file");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -812,7 +916,7 @@ std::vector<DivInstrument*> DivEngine::instrumentFromFile(const char* path) {
|
|||
}
|
||||
} catch (EndOfFileException& e) {
|
||||
lastError="premature end of file";
|
||||
logE("premature end of file!");
|
||||
logE("premature end of file");
|
||||
delete ins;
|
||||
delete[] buf;
|
||||
return ret;
|
||||
|
@ -843,6 +947,8 @@ std::vector<DivInstrument*> DivEngine::instrumentFromFile(const char* path) {
|
|||
format=DIV_INSFORMAT_S3I;
|
||||
} else if (extS==String(".sbi")) {
|
||||
format=DIV_INSFORMAT_SBI;
|
||||
} else if (extS==String(".bnk")) {
|
||||
format=DIV_INSFORMAT_BNK;
|
||||
} else if (extS==String(".opm")) {
|
||||
format=DIV_INSFORMAT_OPM;
|
||||
} else if (extS==String(".ff")) {
|
||||
|
@ -873,6 +979,9 @@ std::vector<DivInstrument*> DivEngine::instrumentFromFile(const char* path) {
|
|||
case DIV_INSFORMAT_SBI:
|
||||
loadSBI(reader,ret,stripPath);
|
||||
break;
|
||||
case DIV_INSFORMAT_BNK:
|
||||
loadBNK(reader, ret, stripPath);
|
||||
break;
|
||||
case DIV_INSFORMAT_FF:
|
||||
loadFF(reader,ret,stripPath);
|
||||
break;
|
||||
|
|
|
@ -486,6 +486,27 @@ void DivInstrument::putInsData(SafeWriter* w) {
|
|||
w->writeC(ws.param2);
|
||||
w->writeC(ws.param3);
|
||||
w->writeC(ws.param4);
|
||||
|
||||
// other macro modes
|
||||
w->writeC(std.volMacro.mode);
|
||||
w->writeC(std.dutyMacro.mode);
|
||||
w->writeC(std.waveMacro.mode);
|
||||
w->writeC(std.pitchMacro.mode);
|
||||
w->writeC(std.ex1Macro.mode);
|
||||
w->writeC(std.ex2Macro.mode);
|
||||
w->writeC(std.ex3Macro.mode);
|
||||
w->writeC(std.algMacro.mode);
|
||||
w->writeC(std.fbMacro.mode);
|
||||
w->writeC(std.fmsMacro.mode);
|
||||
w->writeC(std.amsMacro.mode);
|
||||
w->writeC(std.panLMacro.mode);
|
||||
w->writeC(std.panRMacro.mode);
|
||||
w->writeC(std.phaseResetMacro.mode);
|
||||
w->writeC(std.ex4Macro.mode);
|
||||
w->writeC(std.ex5Macro.mode);
|
||||
w->writeC(std.ex6Macro.mode);
|
||||
w->writeC(std.ex7Macro.mode);
|
||||
w->writeC(std.ex8Macro.mode);
|
||||
}
|
||||
|
||||
DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) {
|
||||
|
@ -962,6 +983,29 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) {
|
|||
ws.param4=reader.readC();
|
||||
}
|
||||
|
||||
// other macro modes
|
||||
if (version>=84) {
|
||||
std.volMacro.mode=reader.readC();
|
||||
std.dutyMacro.mode=reader.readC();
|
||||
std.waveMacro.mode=reader.readC();
|
||||
std.pitchMacro.mode=reader.readC();
|
||||
std.ex1Macro.mode=reader.readC();
|
||||
std.ex2Macro.mode=reader.readC();
|
||||
std.ex3Macro.mode=reader.readC();
|
||||
std.algMacro.mode=reader.readC();
|
||||
std.fbMacro.mode=reader.readC();
|
||||
std.fmsMacro.mode=reader.readC();
|
||||
std.amsMacro.mode=reader.readC();
|
||||
std.panLMacro.mode=reader.readC();
|
||||
std.panRMacro.mode=reader.readC();
|
||||
std.phaseResetMacro.mode=reader.readC();
|
||||
std.ex4Macro.mode=reader.readC();
|
||||
std.ex5Macro.mode=reader.readC();
|
||||
std.ex6Macro.mode=reader.readC();
|
||||
std.ex7Macro.mode=reader.readC();
|
||||
std.ex8Macro.mode=reader.readC();
|
||||
}
|
||||
|
||||
return DIV_DATA_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -302,6 +302,7 @@ struct DivInstrumentAmiga {
|
|||
};
|
||||
|
||||
short initSample;
|
||||
bool reversed;
|
||||
bool useNoteMap;
|
||||
bool useWave;
|
||||
unsigned char waveLen;
|
||||
|
@ -309,6 +310,7 @@ struct DivInstrumentAmiga {
|
|||
|
||||
DivInstrumentAmiga():
|
||||
initSample(0),
|
||||
reversed(false),
|
||||
useNoteMap(false),
|
||||
useWave(false),
|
||||
waveLen(31) {}
|
||||
|
|
|
@ -21,14 +21,19 @@
|
|||
#include "instrument.h"
|
||||
#include "engine.h"
|
||||
|
||||
void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released) {
|
||||
void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released, bool tick) {
|
||||
if (!tick) {
|
||||
had=false;
|
||||
return;
|
||||
}
|
||||
if (finished) {
|
||||
finished=false;
|
||||
}
|
||||
if (had!=has) {
|
||||
if (actualHad!=has) {
|
||||
finished=true;
|
||||
}
|
||||
had=has;
|
||||
actualHad=has;
|
||||
had=actualHad;
|
||||
if (has) {
|
||||
val=source.val[pos++];
|
||||
if (source.rel>=0 && pos>source.rel && !released) {
|
||||
|
@ -52,17 +57,18 @@ void DivMacroInt::next() {
|
|||
if (ins==NULL) return;
|
||||
// run macros
|
||||
// TODO: potentially get rid of list to avoid allocations
|
||||
if (--subTick<=0) {
|
||||
subTick--;
|
||||
for (size_t i=0; i<macroListLen; i++) {
|
||||
if (macroList[i]!=NULL && macroSource[i]!=NULL) {
|
||||
macroList[i]->doMacro(*macroSource[i],released,subTick==0);
|
||||
}
|
||||
}
|
||||
if (subTick<=0) {
|
||||
if (e==NULL) {
|
||||
subTick=1;
|
||||
} else {
|
||||
subTick=e->tickMult;
|
||||
}
|
||||
for (size_t i=0; i<macroListLen; i++) {
|
||||
if (macroList[i]!=NULL && macroSource[i]!=NULL) {
|
||||
macroList[i]->doMacro(*macroSource[i],released);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,6 +91,7 @@ void DivMacroInt::init(DivInstrument* which) {
|
|||
if (macroList[i]!=NULL) macroList[i]->init();
|
||||
}
|
||||
macroListLen=0;
|
||||
subTick=1;
|
||||
|
||||
released=false;
|
||||
|
||||
|
|
|
@ -27,17 +27,17 @@ class DivEngine;
|
|||
struct DivMacroStruct {
|
||||
int pos;
|
||||
int val;
|
||||
bool has, had, finished, will;
|
||||
bool has, had, actualHad, finished, will;
|
||||
unsigned int mode;
|
||||
void doMacro(DivInstrumentMacro& source, bool released);
|
||||
void doMacro(DivInstrumentMacro& source, bool released, bool tick);
|
||||
void init() {
|
||||
pos=mode=0;
|
||||
has=had=will=false;
|
||||
has=had=actualHad=will=false;
|
||||
// TODO: test whether this breaks anything?
|
||||
val=0;
|
||||
}
|
||||
void prepare(DivInstrumentMacro& source) {
|
||||
has=had=will=true;
|
||||
has=had=actualHad=will=true;
|
||||
mode=source.mode;
|
||||
}
|
||||
DivMacroStruct():
|
||||
|
@ -45,6 +45,7 @@ struct DivMacroStruct {
|
|||
val(0),
|
||||
has(false),
|
||||
had(false),
|
||||
actualHad(false),
|
||||
finished(false),
|
||||
will(false),
|
||||
mode(0) {}
|
||||
|
@ -128,7 +129,7 @@ class DivMacroInt {
|
|||
e(NULL),
|
||||
ins(NULL),
|
||||
macroListLen(0),
|
||||
subTick(0),
|
||||
subTick(1),
|
||||
released(false),
|
||||
vol(),
|
||||
arp(),
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
void DivDispatch::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
}
|
||||
|
||||
void DivDispatch::tick() {
|
||||
void DivDispatch::tick(bool sysTick) {
|
||||
}
|
||||
|
||||
void* DivDispatch::getChanState(int chan) {
|
||||
|
|
|
@ -108,7 +108,9 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le
|
|||
} else {
|
||||
DivSample* s=parent->getSample(chan[i].sample);
|
||||
if (s->samples>0) {
|
||||
if (chan[i].audPos<s->samples) {
|
||||
writeAudDat(s->data8[chan[i].audPos++]);
|
||||
}
|
||||
if (((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && chan[i].audPos>=s->loopEnd) || (chan[i].audPos>=s->samples) || (chan[i].audPos>=131071)) {
|
||||
if (s->isLoopable()) {
|
||||
chan[i].audPos=s->loopStart;
|
||||
|
@ -155,7 +157,7 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformAmiga::tick() {
|
||||
void DivPlatformAmiga::tick(bool sysTick) {
|
||||
for (int i=0; i<4; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
|
@ -204,7 +206,7 @@ void DivPlatformAmiga::tick() {
|
|||
}
|
||||
}
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
//DivInstrument* ins=parent->getIns(chan[i].ins);
|
||||
//DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AMIGA);
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)+chan[i].std.pitch.val;
|
||||
if (chan[i].freq>4095) chan[i].freq=4095;
|
||||
if (chan[i].freq<0) chan[i].freq=0;
|
||||
|
@ -222,7 +224,7 @@ void DivPlatformAmiga::tick() {
|
|||
int DivPlatformAmiga::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
|
||||
double off=1.0;
|
||||
if (ins->amiga.useWave) {
|
||||
chan[c.chan].useWave=true;
|
||||
|
@ -312,7 +314,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) {
|
|||
chan[c.chan].ws.changeWave1(chan[c.chan].wave);
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
|
||||
chan[c.chan].sample=ins->amiga.initSample;
|
||||
double off=1.0;
|
||||
if (!chan[c.chan].useWave && chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||
|
@ -362,7 +364,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) {
|
|||
}
|
||||
case DIV_CMD_PRE_PORTA:
|
||||
if (chan[c.chan].active && c.value2) {
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
|
|
|
@ -88,7 +88,7 @@ class DivPlatformAmiga: public DivDispatch {
|
|||
void* getChanState(int chan);
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool isStereo();
|
||||
bool keyOffAffectsArp(int ch);
|
||||
|
|
|
@ -219,7 +219,7 @@ inline int hScale(int note) {
|
|||
return ((note/12)<<4)+(noteMap[note%12]);
|
||||
}
|
||||
|
||||
void DivPlatformArcade::tick() {
|
||||
void DivPlatformArcade::tick(bool sysTick) {
|
||||
for (int i=0; i<8; i++) {
|
||||
chan[i].std.next();
|
||||
|
||||
|
@ -264,6 +264,20 @@ void DivPlatformArcade::tick() {
|
|||
rWrite(0x1b,chan[i].std.wave.val&3);
|
||||
}
|
||||
|
||||
if (chan[i].std.panL.had) {
|
||||
chan[i].chVolL=(chan[i].std.panL.val&2)>>1;
|
||||
chan[i].chVolR=chan[i].std.panL.val&1;
|
||||
if (isMuted[i]) {
|
||||
rWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
|
||||
} 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 (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val==1) {
|
||||
chan[i].keyOn=true;
|
||||
|
@ -432,7 +446,7 @@ void DivPlatformArcade::muteChannel(int ch, bool mute) {
|
|||
int DivPlatformArcade::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
|
||||
if (chan[c.chan].insChanged) {
|
||||
chan[c.chan].state=ins->fm;
|
||||
|
|
|
@ -107,7 +107,7 @@ class DivPlatformArcade: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
void notifyInsChange(int ins);
|
||||
void setFlags(unsigned int flags);
|
||||
|
|
|
@ -172,7 +172,7 @@ void DivPlatformAY8910::updateOutSel(bool immediate) {
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformAY8910::tick() {
|
||||
void DivPlatformAY8910::tick(bool sysTick) {
|
||||
// PSG
|
||||
for (int i=0; i<3; i++) {
|
||||
chan[i].std.next();
|
||||
|
@ -215,6 +215,9 @@ void DivPlatformAY8910::tick() {
|
|||
rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2));
|
||||
}
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val==1) {
|
||||
oldWrites[0x08+i]=-1;
|
||||
|
@ -291,7 +294,7 @@ void DivPlatformAY8910::tick() {
|
|||
int DivPlatformAY8910::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AY);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
|
@ -454,7 +457,7 @@ 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].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_AY));
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
|
|
|
@ -90,7 +90,7 @@ class DivPlatformAY8910: public DivDispatch {
|
|||
void flushWrites();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
void setFlags(unsigned int flags);
|
||||
bool isStereo();
|
||||
|
|
|
@ -187,7 +187,7 @@ const unsigned char regMode[3]={
|
|||
0x0d, 0x14, 0x15
|
||||
};
|
||||
|
||||
void DivPlatformAY8930::tick() {
|
||||
void DivPlatformAY8930::tick(bool sysTick) {
|
||||
// PSG
|
||||
for (int i=0; i<3; i++) {
|
||||
chan[i].std.next();
|
||||
|
@ -226,6 +226,9 @@ void DivPlatformAY8930::tick() {
|
|||
rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode&4)<<3));
|
||||
}
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val==1) {
|
||||
oldWrites[0x08+i]=-1;
|
||||
|
@ -315,7 +318,7 @@ void DivPlatformAY8930::tick() {
|
|||
int DivPlatformAY8930::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AY8930);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
|
@ -479,7 +482,7 @@ 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].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_AY8930));
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
|
|
|
@ -78,7 +78,7 @@ class DivPlatformAY8930: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
void setFlags(unsigned int flags);
|
||||
bool isStereo();
|
||||
|
|
|
@ -81,7 +81,7 @@ void DivPlatformBubSysWSG::updateWave(int ch) {
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformBubSysWSG::tick() {
|
||||
void DivPlatformBubSysWSG::tick(bool sysTick) {
|
||||
for (int i=0; i<2; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
|
@ -110,13 +110,16 @@ void DivPlatformBubSysWSG::tick() {
|
|||
if (!chan[i].keyOff) chan[i].keyOn=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].active) {
|
||||
if (chan[i].ws.tick()) {
|
||||
updateWave(i);
|
||||
}
|
||||
}
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
//DivInstrument* ins=parent->getIns(chan[i].ins);
|
||||
//DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SCC);
|
||||
chan[i].freq=0x1000-parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)+chan[i].std.pitch.val;
|
||||
if (chan[i].freq<0) chan[i].freq=0;
|
||||
if (chan[i].freq>4095) chan[i].freq=4095;
|
||||
|
@ -139,7 +142,7 @@ void DivPlatformBubSysWSG::tick() {
|
|||
int DivPlatformBubSysWSG::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SCC);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
|
@ -225,7 +228,7 @@ 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].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_SCC));
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
|
|
|
@ -67,7 +67,7 @@ class DivPlatformBubSysWSG: public DivDispatch {
|
|||
int getRegisterPoolDepth();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool isStereo();
|
||||
bool keyOffAffectsArp(int ch);
|
||||
|
|
|
@ -122,11 +122,11 @@ void DivPlatformC64::updateFilter() {
|
|||
rWrite(0x18,(filtControl<<4)|vol);
|
||||
}
|
||||
|
||||
void DivPlatformC64::tick() {
|
||||
void DivPlatformC64::tick(bool sysTick) {
|
||||
for (int i=0; i<3; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_C64);
|
||||
if (ins->c64.volIsCutoff) {
|
||||
if (ins->c64.filterIsAbs) {
|
||||
filtCut=MIN(2047,chan[i].std.vol.val);
|
||||
|
@ -157,7 +157,7 @@ void DivPlatformC64::tick() {
|
|||
}
|
||||
}
|
||||
if (chan[i].std.duty.had) {
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_C64);
|
||||
if (ins->c64.dutyIsAbs) {
|
||||
chan[i].duty=chan[i].std.duty.val;
|
||||
} else {
|
||||
|
@ -166,19 +166,24 @@ void DivPlatformC64::tick() {
|
|||
rWrite(i*7+2,chan[i].duty&0xff);
|
||||
rWrite(i*7+3,chan[i].duty>>8);
|
||||
}
|
||||
if (sysTick) {
|
||||
if (chan[i].testWhen>0) {
|
||||
if (--chan[i].testWhen<1) {
|
||||
if (!chan[i].resetMask) {
|
||||
if (!chan[i].resetMask && !chan[i].inPorta) {
|
||||
rWrite(i*7+5,0);
|
||||
rWrite(i*7+6,0);
|
||||
rWrite(i*7+4,(chan[i].wave<<4)|8|(chan[i].ring<<2)|(chan[i].sync<<1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[i].std.wave.had) {
|
||||
chan[i].wave=chan[i].std.wave.val;
|
||||
rWrite(i*7+4,(chan[i].wave<<4)|(chan[i].ring<<2)|(chan[i].sync<<1)|(int)(chan[i].active));
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].std.ex1.had) {
|
||||
filtControl=chan[i].std.ex1.val&15;
|
||||
updateFilter();
|
||||
|
@ -218,7 +223,7 @@ void DivPlatformC64::tick() {
|
|||
int DivPlatformC64::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_C64);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
|
@ -339,8 +344,8 @@ int DivPlatformC64::dispatch(DivCommand c) {
|
|||
break;
|
||||
case DIV_CMD_PRE_PORTA:
|
||||
if (chan[c.chan].active && c.value2) {
|
||||
if (parent->song.resetMacroOnPorta) {
|
||||
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta || !chan[c.chan].inPorta) {
|
||||
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_C64));
|
||||
chan[c.chan].keyOn=true;
|
||||
}
|
||||
}
|
||||
|
@ -378,7 +383,7 @@ int DivPlatformC64::dispatch(DivCommand c) {
|
|||
break;
|
||||
case DIV_CMD_C64_FILTER_RESET:
|
||||
if (c.value&15) {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_C64);
|
||||
if (ins->c64.initFilter) {
|
||||
filtCut=ins->c64.cut;
|
||||
updateFilter();
|
||||
|
@ -388,7 +393,7 @@ int DivPlatformC64::dispatch(DivCommand c) {
|
|||
break;
|
||||
case DIV_CMD_C64_DUTY_RESET:
|
||||
if (c.value&15) {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_C64);
|
||||
chan[c.chan].duty=ins->c64.duty;
|
||||
rWrite(c.chan*7+2,chan[c.chan].duty&0xff);
|
||||
rWrite(c.chan*7+3,chan[c.chan].duty>>8);
|
||||
|
|
|
@ -83,7 +83,7 @@ class DivPlatformC64: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
void setFlags(unsigned int flags);
|
||||
void notifyInsChange(int ins);
|
||||
|
|
|
@ -38,10 +38,12 @@ void DivPlatformDummy::muteChannel(int ch, bool mute) {
|
|||
isMuted[ch]=mute;
|
||||
}
|
||||
|
||||
void DivPlatformDummy::tick() {
|
||||
void DivPlatformDummy::tick(bool sysTick) {
|
||||
for (unsigned char i=0; i<chans; i++) {
|
||||
if (sysTick) {
|
||||
chan[i].amp-=3;
|
||||
if (chan[i].amp<16) chan[i].amp=16;
|
||||
}
|
||||
|
||||
if (chan[i].freqChanged) {
|
||||
chan[i].freqChanged=false;
|
||||
|
|
|
@ -41,7 +41,7 @@ class DivPlatformDummy: public DivDispatch {
|
|||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
void reset();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
~DivPlatformDummy();
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include <math.h>
|
||||
#include <map>
|
||||
|
||||
#define CHIP_FREQBASE (16*2048)
|
||||
#define CHIP_FREQBASE (16*2048*(chanMax+1))
|
||||
#define NOTE_ES5506(c,note) (chan[c].pcm.freqOffs*NOTE_FREQUENCY(note))
|
||||
|
||||
#define rWrite(a,...) {if(!skipRegisterWrites) {hostIntf32.emplace(4,(a),__VA_ARGS__); }}
|
||||
|
@ -106,14 +106,40 @@ const char** DivPlatformES5506::getRegisterSheet() {
|
|||
const char* DivPlatformES5506::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xx: Set echo feedback level (00 to FF)";
|
||||
return "10xx: Change waveform";
|
||||
break;
|
||||
case 0x11:
|
||||
return "11xx: Set channel echo level (00 to FF)";
|
||||
return "11xx: Set filter mode (00 to 03)";
|
||||
break;
|
||||
case 0x20:
|
||||
return "20xx: Set envelope count (000 to 0FF)";
|
||||
break;
|
||||
case 0x21:
|
||||
return "21xx: Set envelope count (100 to 1FF)";
|
||||
break;
|
||||
case 0x22:
|
||||
return "22xx: Set envelope left volume ramp (signed)";
|
||||
break;
|
||||
case 0x23:
|
||||
return "23xx: Set envelope right volume ramp (signed)";
|
||||
break;
|
||||
case 0x24:
|
||||
return "24xx: Set envelope k1 ramp (signed)";
|
||||
break;
|
||||
case 0x25:
|
||||
return "25xx: Set envelope k1 ramp (signed, slower)";
|
||||
break;
|
||||
case 0x26:
|
||||
return "26xx: Set envelope k2 ramp (signed)";
|
||||
break;
|
||||
case 0x27:
|
||||
return "27xx: Set envelope k2 ramp (signed, slower)";
|
||||
break;
|
||||
default:
|
||||
if ((effect&0xf0)==0x30) {
|
||||
return "3xxx: Set echo delay buffer length (000 to AA5)";
|
||||
return "3xxx: Set filter K1";
|
||||
} else if ((effect&0xf0)==0x40) {
|
||||
return "4xxx: Set filter K2";
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
@ -190,9 +216,9 @@ void DivPlatformES5506::e(bool state)
|
|||
irqTrigger=false;
|
||||
if ((irqv&0x80)==0) {
|
||||
unsigned char ch=irqv&0x1f;
|
||||
if (chan[ch].isReversed) { // Reversed loop
|
||||
pageWriteMask(0x00|ch,0x5f,0x00,0x48,0x78);
|
||||
chan[ch].isReversed=false;
|
||||
if (chan[ch].isReverseLoop) { // Reversed loop
|
||||
pageWriteMask(0x00|ch,0x5f,0x00,(chan[ch].pcm.reversed?0x0040:0x0000)|0x08,0x78);
|
||||
chan[ch].isReverseLoop=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -204,7 +230,7 @@ void DivPlatformES5506::irqb(bool state) {
|
|||
irqTrigger=true;
|
||||
}
|
||||
|
||||
void DivPlatformES5506::tick() {
|
||||
void DivPlatformES5506::tick(bool sysTick) {
|
||||
for (int i=0; i<=chanMax; i++) {
|
||||
chan[i].std.next();
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins);
|
||||
|
@ -252,6 +278,104 @@ void DivPlatformES5506::tick() {
|
|||
chan[i].keyOn=true;
|
||||
}
|
||||
}
|
||||
// filter macros
|
||||
if (chan[i].std.duty.had) {
|
||||
if (chan[i].filter.mode!=DivInstrumentES5506::Filter::FilterMode(chan[i].std.duty.val&3)) {
|
||||
chan[i].filter.mode=DivInstrumentES5506::Filter::FilterMode(chan[i].std.duty.val&3);
|
||||
chan[i].filterChanged.mode=1;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.ex1.had) {
|
||||
switch (chan[i].std.ex1.mode) {
|
||||
case 0: // relative
|
||||
if (chan[i].k1Offs!=chan[i].std.ex1.val) {
|
||||
chan[i].k1Offs=chan[i].std.ex1.val;
|
||||
chan[i].filterChanged.k1=1;
|
||||
}
|
||||
case 1: // absolute
|
||||
if (chan[i].filter.k1!=(chan[i].std.ex1.val&0xffff)) {
|
||||
chan[i].filter.k1=chan[i].std.ex1.val&0xffff;
|
||||
chan[i].filterChanged.k1=1;
|
||||
}
|
||||
break;
|
||||
case 2: { // delta
|
||||
signed int next_k1=MAX(0,MIN(65535,chan[i].filter.k1+chan[i].std.ex1.val));
|
||||
if (chan[i].filter.k1!=next_k1) {
|
||||
chan[i].filter.k1=next_k1;
|
||||
chan[i].filterChanged.k1=1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.ex2.had) {
|
||||
switch (chan[i].std.ex2.mode) {
|
||||
case 0: // relative
|
||||
if (chan[i].k2Offs!=chan[i].std.ex1.val) {
|
||||
chan[i].k2Offs=chan[i].std.ex1.val;
|
||||
chan[i].filterChanged.k2=1;
|
||||
}
|
||||
case 1: // absolute
|
||||
if (chan[i].filter.k2!=(chan[i].std.ex2.val&0xffff)) {
|
||||
chan[i].filter.k2=chan[i].std.ex2.val&0xffff;
|
||||
chan[i].filterChanged.k2=1;
|
||||
}
|
||||
break;
|
||||
case 2: { // delta
|
||||
signed int next_k2=MAX(0,MIN(65535,chan[i].filter.k2+chan[i].std.ex2.val));
|
||||
if (chan[i].filter.k2!=next_k2) {
|
||||
chan[i].filter.k2=next_k2;
|
||||
chan[i].filterChanged.k2=1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// envelope macros
|
||||
if (chan[i].std.ex3.had) {
|
||||
if (chan[i].envelope.ecount!=(chan[i].std.ex3.val&0x1ff)) {
|
||||
chan[i].envelope.ecount=chan[i].std.ex3.val&0x1ff;
|
||||
chan[i].envChanged.ecount=1;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.ex4.had) {
|
||||
if (chan[i].envelope.lVRamp!=chan[i].std.ex4.val) {
|
||||
chan[i].envelope.lVRamp=chan[i].std.ex4.val;
|
||||
chan[i].envChanged.lVRamp=1;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.ex5.had) {
|
||||
if (chan[i].envelope.rVRamp!=chan[i].std.ex5.val) {
|
||||
chan[i].envelope.rVRamp=chan[i].std.ex5.val;
|
||||
chan[i].envChanged.rVRamp=1;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.ex6.had) {
|
||||
if (chan[i].envelope.k1Ramp!=chan[i].std.ex6.val) {
|
||||
chan[i].envelope.k1Ramp=chan[i].std.ex6.val;
|
||||
chan[i].envChanged.k1Ramp=1;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.ex7.had) {
|
||||
if (chan[i].envelope.k2Ramp!=chan[i].std.ex7.val) {
|
||||
chan[i].envelope.k2Ramp=chan[i].std.ex7.val;
|
||||
chan[i].envChanged.k2Ramp=1;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.ex8.had) {
|
||||
if (chan[i].envelope.k1Slow!=(chan[i].std.ex8.val&1)) {
|
||||
chan[i].envelope.k1Slow=chan[i].std.ex8.val&1;
|
||||
chan[i].envChanged.k1Ramp=1;
|
||||
}
|
||||
if (chan[i].envelope.k2Slow!=(chan[i].std.ex8.val&2)) {
|
||||
chan[i].envelope.k2Slow=chan[i].std.ex8.val&2;
|
||||
chan[i].envChanged.k2Ramp=1;
|
||||
}
|
||||
}
|
||||
// update registers
|
||||
if (chan[i].volChanged) {
|
||||
if (!isMuted[i]) { // calculate volume (16 bit)
|
||||
|
@ -267,72 +391,96 @@ void DivPlatformES5506::tick() {
|
|||
}
|
||||
chan[i].volChanged=false;
|
||||
}
|
||||
if (chan[i].filterChanged) {
|
||||
pageWriteMask(0x00|i,0x5f,0x00,(chan[i].filter.mode<<8),0x0300);
|
||||
if (chan[i].filterChanged.changed) {
|
||||
if (!chan[i].keyOn) {
|
||||
if (chan[i].filterChanged.mode) {
|
||||
pageWriteMask(0x00|i,0x5f,0x00,(chan[i].filter.mode<<8),0x0300);
|
||||
}
|
||||
if (chan[i].filterChanged.k2) {
|
||||
if (chan[i].std.ex2.mode==0) { // Relative
|
||||
pageWrite(0x00|i,0x07,MAX(0,MIN(65535,chan[i].filter.k2+chan[i].k2Offs)));
|
||||
} else {
|
||||
pageWrite(0x00|i,0x07,chan[i].filter.k2);
|
||||
}
|
||||
}
|
||||
if (chan[i].filterChanged.k1) {
|
||||
if (chan[i].std.ex1.mode==0) { // Relative
|
||||
pageWrite(0x00|i,0x09,MAX(0,MIN(65535,chan[i].filter.k1+chan[i].k1Offs)));
|
||||
} else {
|
||||
pageWrite(0x00|i,0x09,chan[i].filter.k1);
|
||||
}
|
||||
chan[i].filterChanged=false;
|
||||
}
|
||||
if (chan[i].envChanged) {
|
||||
}
|
||||
chan[i].filterChanged.changed=0;
|
||||
}
|
||||
if (chan[i].envChanged.changed) {
|
||||
if (!chan[i].keyOn) {
|
||||
if (chan[i].envChanged.lVRamp) {
|
||||
pageWrite(0x00|i,0x03,((unsigned char)chan[i].envelope.lVRamp)<<8);
|
||||
}
|
||||
if (chan[i].envChanged.rVRamp) {
|
||||
pageWrite(0x00|i,0x05,((unsigned char)chan[i].envelope.rVRamp)<<8);
|
||||
}
|
||||
if (chan[i].envChanged.ecount) {
|
||||
pageWrite(0x00|i,0x06,chan[i].envelope.ecount);
|
||||
}
|
||||
chan[i].envChanged=false;
|
||||
}
|
||||
if (chan[i].rampChanged) {
|
||||
if (!chan[i].keyOn) {
|
||||
pageWrite(0x00|i,0x03,((unsigned char)chan[i].envelope.lVRamp)<<8);
|
||||
pageWrite(0x00|i,0x05,((unsigned char)chan[i].envelope.rVRamp)<<8);
|
||||
pageWrite(0x00|i,0x0a,(((unsigned char)chan[i].envelope.k1Ramp)<<8)|(chan[i].envelope.k1Slow?1:0));
|
||||
if (chan[i].envChanged.k2Ramp) {
|
||||
pageWrite(0x00|i,0x08,(((unsigned char)chan[i].envelope.k2Ramp)<<8)|(chan[i].envelope.k2Slow?1:0));
|
||||
}
|
||||
chan[i].rampChanged=false;
|
||||
if (chan[i].envChanged.k1Ramp) {
|
||||
pageWrite(0x00|i,0x0a,(((unsigned char)chan[i].envelope.k1Ramp)<<8)|(chan[i].envelope.k1Slow?1:0));
|
||||
}
|
||||
}
|
||||
chan[i].envChanged.changed=0;
|
||||
}
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq*(chanMax+1),chan[i].pitch,false)+chan[i].std.pitch.val;
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false)+chan[i].std.pitch.val;
|
||||
if (chan[i].freq<0) chan[i].freq=0;
|
||||
if (chan[i].freq>0x1ffff) chan[i].freq=0x1ffff;
|
||||
if (chan[i].keyOn) {
|
||||
if (chan[i].pcm.index>=0) {
|
||||
pageWriteMask(0x00|i,0x5f,0x00,0x0303); // Wipeout CR
|
||||
pageWrite(0x00|i,0x06,0); // Clear ECOUNT
|
||||
pageWrite(0x20|i,0x03,chan[i].pcm.base); // Set ACCUM to start address
|
||||
pageWrite(0x00|i,0x09,0xffff); // Set K1 and K2 to 0xffff
|
||||
pageWrite(0x00|i,0x07,0xffff,~0,(chanMax+1)*4*2); // needs to 4 sample period delay
|
||||
pageWrite(0x20|i,0x03,chan[i].pcm.reversed?chan[i].pcm.end:chan[i].pcm.start); // Set ACCUM to start address
|
||||
pageWrite(0x00|i,0x07,0xffff); // Set K1 and K2 to 0xffff
|
||||
pageWrite(0x00|i,0x09,0xffff);
|
||||
pageWrite(0x00|i,0x01,chan[i].freq);
|
||||
if (chan[i].pcm.loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) {
|
||||
pageWrite(0x20|i,0x01,chan[i].pcm.loopStart);
|
||||
}
|
||||
pageWrite(0x20|i,0x02,chan[i].pcm.loopEnd);
|
||||
pageWrite(0x20|i,0x01,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT)?chan[i].pcm.start:chan[i].pcm.loopStart);
|
||||
pageWrite(0x20|i,0x02,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT)?chan[i].pcm.end:chan[i].pcm.loopEnd);
|
||||
// initialize envelope
|
||||
pageWrite(0x00|i,0x03,((unsigned char)chan[i].envelope.lVRamp)<<8);
|
||||
pageWrite(0x00|i,0x05,((unsigned char)chan[i].envelope.rVRamp)<<8);
|
||||
pageWrite(0x00|i,0x0a,(((unsigned char)chan[i].envelope.k1Ramp)<<8)|(chan[i].envelope.k1Slow?1:0));
|
||||
pageWrite(0x00|i,0x08,(((unsigned char)chan[i].envelope.k2Ramp)<<8)|(chan[i].envelope.k2Slow?1:0));
|
||||
pageWrite(0x00|i,0x08,(((unsigned char)chan[i].envelope.k2Ramp)<<8)|(chan[i].envelope.k2Slow?1:0),~0,(chanMax+1)*4*2); // needs to 4 sample period delay
|
||||
// initialize filter
|
||||
pageWriteMask(0x00|i,0x5f,0x00,(chan[i].pcm.bank<<14)|(chan[i].filter.mode<<8),0xc300);
|
||||
pageWrite(0x00|i,0x09,chan[i].filter.k1);
|
||||
if ((chan[i].std.ex2.mode==0) && (chan[i].std.ex2.had)) {
|
||||
pageWrite(0x00|i,0x07,MAX(0,MIN(65535,chan[i].filter.k2+chan[i].k2Offs)));
|
||||
} else {
|
||||
pageWrite(0x00|i,0x07,chan[i].filter.k2);
|
||||
}
|
||||
if ((chan[i].std.ex1.mode==0) && (chan[i].std.ex1.had)) {
|
||||
pageWrite(0x00|i,0x09,MAX(0,MIN(65535,chan[i].filter.k1+chan[i].k1Offs)));
|
||||
} else {
|
||||
pageWrite(0x00|i,0x09,chan[i].filter.k1);
|
||||
}
|
||||
pageWrite(0x00|i,0x02,chan[i].resLVol);
|
||||
pageWrite(0x00|i,0x04,chan[i].resRVol);
|
||||
unsigned int loopFlag=0x0000;
|
||||
chan[i].isReversed=false;
|
||||
unsigned int loopFlag=chan[i].pcm.reversed?0x0040:0x0000;
|
||||
chan[i].isReverseLoop=false;
|
||||
switch (chan[i].pcm.loopMode) {
|
||||
case DIV_SAMPLE_LOOPMODE_ONESHOT: // One shot (no loop)
|
||||
default:
|
||||
loopFlag=0x0000;
|
||||
break;
|
||||
case DIV_SAMPLE_LOOPMODE_FOWARD: // Foward loop
|
||||
loopFlag=0x0008;
|
||||
loopFlag|=0x0008;
|
||||
break;
|
||||
case DIV_SAMPLE_LOOPMODE_BACKWARD: // Backward loop: IRQ enable
|
||||
loopFlag=0x0038;
|
||||
chan[i].isReversed=true;
|
||||
loopFlag|=0x0038;
|
||||
chan[i].isReverseLoop=true;
|
||||
break;
|
||||
case DIV_SAMPLE_LOOPMODE_PINGPONG: // Pingpong loop: Hardware support
|
||||
loopFlag=0x0018;
|
||||
loopFlag|=0x0018;
|
||||
break;
|
||||
}
|
||||
// Run sample
|
||||
|
@ -341,7 +489,7 @@ void DivPlatformES5506::tick() {
|
|||
}
|
||||
}
|
||||
if (chan[i].keyOff) {
|
||||
pageWriteMask(0x00|i,0x5f,0x00,0x0003); // Wipeout CR
|
||||
pageWriteMask(0x00|i,0x5f,0x00,0x0303); // Wipeout CR
|
||||
} else if (chan[i].active) {
|
||||
pageWrite(0x00|i,0x01,chan[i].freq);
|
||||
}
|
||||
|
@ -356,6 +504,7 @@ int DivPlatformES5506::dispatch(DivCommand c) {
|
|||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
if (chan[c.chan].insChanged) {
|
||||
chan[c.chan].sample=ins->amiga.useNoteMap?ins->amiga.noteMap[c.value].ind:ins->amiga.initSample;
|
||||
double off=1.0;
|
||||
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||
|
@ -366,13 +515,18 @@ int DivPlatformES5506::dispatch(DivCommand c) {
|
|||
} else {
|
||||
off=ins->amiga.useNoteMap?((double)ins->amiga.noteMap[c.value].freq/((double)s->centerRate*pow(2.0,((double)c.value-48.0)/12.0))):((double)s->centerRate/8363.0);
|
||||
}
|
||||
unsigned int base=s->offES5506<<10;
|
||||
const unsigned int start=s->offES5506<<10;
|
||||
const unsigned int length=s->samples-1;
|
||||
const unsigned int end=start+(length<<11);
|
||||
chan[c.chan].pcm.loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOPMODE_ONESHOT;
|
||||
chan[c.chan].pcm.freqOffs=off;
|
||||
chan[c.chan].pcm.reversed=ins->amiga.reversed;
|
||||
chan[c.chan].pcm.bank=(s->offES5506>>22)&3;
|
||||
chan[c.chan].pcm.base=base;
|
||||
chan[c.chan].pcm.loopStart=(base+(s->loopStart<<11))&0xfffff800;
|
||||
chan[c.chan].pcm.loopEnd=((base+(s->loopEnd<<11))-0x800)&0xffffff80;
|
||||
chan[c.chan].pcm.start=start;
|
||||
chan[c.chan].pcm.end=end;
|
||||
chan[c.chan].pcm.length=length;
|
||||
chan[c.chan].pcm.loopStart=(start+(s->loopStart<<11))&0xfffff800;
|
||||
chan[c.chan].pcm.loopEnd=(start+((s->loopEnd-1)<<11))&0xffffff80;
|
||||
chan[c.chan].filter=ins->es5506.filter;
|
||||
chan[c.chan].envelope=ins->es5506.envelope;
|
||||
} else {
|
||||
|
@ -381,6 +535,8 @@ int DivPlatformES5506::dispatch(DivCommand c) {
|
|||
chan[c.chan].filter=DivInstrumentES5506::Filter();
|
||||
chan[c.chan].envelope=DivInstrumentES5506::Envelope();
|
||||
}
|
||||
chan[c.chan].insChanged=false;
|
||||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_ES5506(c.chan,c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
|
@ -466,6 +622,45 @@ int DivPlatformES5506::dispatch(DivCommand c) {
|
|||
chan[c.chan].pitch=c.value;
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_WAVE:
|
||||
// reserved for useWave
|
||||
break;
|
||||
// Filter commands
|
||||
case DIV_CMD_ES5506_FILTER_MODE:
|
||||
chan[c.chan].filter.mode=DivInstrumentES5506::Filter::FilterMode(c.value&3);
|
||||
chan[c.chan].filterChanged.mode=1;
|
||||
break;
|
||||
case DIV_CMD_ES5506_FILTER_K1:
|
||||
chan[c.chan].filter.k1=(chan[c.chan].filter.k1&0xf)|((c.value&0xfff)<<4);
|
||||
chan[c.chan].filterChanged.k1=1;
|
||||
break;
|
||||
case DIV_CMD_ES5506_FILTER_K2:
|
||||
chan[c.chan].filter.k2=(chan[c.chan].filter.k2&0xf)|((c.value&0xfff)<<4);
|
||||
chan[c.chan].filterChanged.k2=1;
|
||||
break;
|
||||
// Envelope commands
|
||||
case DIV_CMD_ES5506_ENVELOPE_COUNT:
|
||||
chan[c.chan].envelope.ecount=c.value&0x1ff;
|
||||
chan[c.chan].envChanged.ecount=1;
|
||||
break;
|
||||
case DIV_CMD_ES5506_ENVELOPE_LVRAMP:
|
||||
chan[c.chan].envelope.lVRamp=(signed char)(c.value&0xff);
|
||||
chan[c.chan].envChanged.lVRamp=1;
|
||||
break;
|
||||
case DIV_CMD_ES5506_ENVELOPE_RVRAMP:
|
||||
chan[c.chan].envelope.rVRamp=(signed char)(c.value&0xff);
|
||||
chan[c.chan].envChanged.rVRamp=1;
|
||||
break;
|
||||
case DIV_CMD_ES5506_ENVELOPE_K1RAMP:
|
||||
chan[c.chan].envelope.k1Ramp=(signed char)(c.value&0xff);
|
||||
chan[c.chan].envelope.k1Slow=c.value2&1;
|
||||
chan[c.chan].envChanged.k1Ramp=1;
|
||||
break;
|
||||
case DIV_CMD_ES5506_ENVELOPE_K2RAMP:
|
||||
chan[c.chan].envelope.k2Ramp=(signed char)(c.value&0xff);
|
||||
chan[c.chan].envelope.k2Slow=c.value2&1;
|
||||
chan[c.chan].envChanged.k2Ramp=1;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_ES5506(c.chan,c.value2);
|
||||
bool return2=false;
|
||||
|
@ -501,6 +696,16 @@ int DivPlatformES5506::dispatch(DivCommand c) {
|
|||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
case DIV_CMD_SAMPLE_POS: {
|
||||
if (chan[c.chan].useWave) break;
|
||||
if (chan[c.chan].active) {
|
||||
unsigned int pos=chan[c.chan].pcm.reversed?(chan[c.chan].pcm.length-c.value):c.value;
|
||||
if ((chan[c.chan].pcm.reversed && pos>0) || ((!chan[c.chan].pcm.reversed) && pos<chan[c.chan].pcm.length)) {
|
||||
pageWrite(0x20|c.chan,0x03,chan[c.chan].pcm.start+(pos<<11));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_GET_VOLMAX:
|
||||
return 255;
|
||||
break;
|
||||
|
@ -523,6 +728,8 @@ void DivPlatformES5506::forceIns() {
|
|||
chan[i].insChanged=true;
|
||||
chan[i].freqChanged=true;
|
||||
chan[i].volChanged=true;
|
||||
chan[i].filterChanged.changed=(unsigned char)(~0);
|
||||
chan[i].envChanged.changed=(unsigned char)(~0);
|
||||
chan[i].sample=-1;
|
||||
}
|
||||
}
|
||||
|
@ -629,7 +836,7 @@ int DivPlatformES5506::init(DivEngine* p, int channels, int sugRate, unsigned in
|
|||
setFlags(flags);
|
||||
|
||||
chipClock=16000000;
|
||||
rate=chipClock/16;
|
||||
rate=chipClock/16; // 2 E clock tick (16 CLKIN tick) per voice
|
||||
reset();
|
||||
return 32;
|
||||
}
|
||||
|
|
|
@ -32,33 +32,69 @@
|
|||
class DivPlatformES5506: public DivDispatch, public es550x_intf {
|
||||
struct Channel {
|
||||
struct PCM {
|
||||
double freqOffs;
|
||||
int index;
|
||||
double freqOffs;
|
||||
bool reversed;
|
||||
unsigned int bank;
|
||||
unsigned int base;
|
||||
unsigned int start;
|
||||
unsigned int end;
|
||||
unsigned int length;
|
||||
unsigned int loopStart;
|
||||
unsigned int loopEnd;
|
||||
DivSampleLoopMode loopMode;
|
||||
PCM():
|
||||
freqOffs(1.0),
|
||||
index(-1),
|
||||
freqOffs(1.0),
|
||||
reversed(false),
|
||||
bank(0),
|
||||
base(0),
|
||||
start(0),
|
||||
end(0),
|
||||
length(0),
|
||||
loopStart(0),
|
||||
loopEnd(0),
|
||||
loopMode(DIV_SAMPLE_LOOPMODE_ONESHOT) {}
|
||||
} pcm;
|
||||
int freq, baseFreq, pitch;
|
||||
unsigned short audLen;
|
||||
unsigned int audPos;
|
||||
int sample, wave;
|
||||
unsigned char ins;
|
||||
int note;
|
||||
int panning;
|
||||
bool active, insChanged, freqChanged, volChanged, filterChanged, envChanged, rampChanged, keyOn, keyOff, inPorta, useWave, isReversed;
|
||||
int vol, outVol;
|
||||
int lVol, outLVol;
|
||||
int rVol, outRVol;
|
||||
bool active, insChanged, freqChanged, volChanged, keyOn, keyOff, inPorta, useWave, isReverseLoop;
|
||||
|
||||
struct FilterChanged { // Filter changed flags
|
||||
union { // pack flag bits in single byte
|
||||
struct { // flag bits
|
||||
unsigned char mode: 1; // Filter mode
|
||||
unsigned char k1: 1; // K1
|
||||
unsigned char k2: 1; // K2
|
||||
unsigned char dummy: 5; // dummy for bit padding
|
||||
};
|
||||
unsigned char changed; // Packed flags are stored here
|
||||
};
|
||||
|
||||
FilterChanged():
|
||||
changed(0) {}
|
||||
} filterChanged;
|
||||
|
||||
struct EnvChanged { // Envelope changed flags
|
||||
union { // pack flag bits in single byte
|
||||
struct { // flag bits
|
||||
unsigned char ecount: 1; // Envelope count
|
||||
unsigned char lVRamp: 1; // Left volume Ramp
|
||||
unsigned char rVRamp: 1; // Right volume Ramp
|
||||
unsigned char k1Ramp: 1; // K1 Ramp w/Slow flag
|
||||
unsigned char k2Ramp: 1; // K2 Ramp w/Slow flag
|
||||
unsigned char dummy: 3; // dummy for bit padding
|
||||
};
|
||||
unsigned char changed; // Packed flags are stored here
|
||||
};
|
||||
|
||||
EnvChanged():
|
||||
changed(0) {}
|
||||
} envChanged;
|
||||
|
||||
signed int k1Offs, k2Offs;
|
||||
int vol, lVol, rVol;
|
||||
int outVol, outLVol, outRVol;
|
||||
int resLVol, resRVol;
|
||||
DivInstrumentES5506::Filter filter;
|
||||
DivInstrumentES5506::Envelope envelope;
|
||||
|
@ -67,27 +103,23 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf {
|
|||
freq(0),
|
||||
baseFreq(0),
|
||||
pitch(0),
|
||||
audLen(0),
|
||||
audPos(0),
|
||||
sample(-1),
|
||||
ins(-1),
|
||||
note(0),
|
||||
panning(0x10),
|
||||
active(false),
|
||||
insChanged(true),
|
||||
freqChanged(false),
|
||||
volChanged(false),
|
||||
filterChanged(false),
|
||||
envChanged(false),
|
||||
rampChanged(false),
|
||||
keyOn(false),
|
||||
keyOff(false),
|
||||
inPorta(false),
|
||||
vol(0xffff),
|
||||
k1Offs(0),
|
||||
k2Offs(0),
|
||||
vol(0xff),
|
||||
lVol(0xf),
|
||||
rVol(0xf),
|
||||
outVol(0xffff),
|
||||
lVol(0xffff),
|
||||
outLVol(0xffff),
|
||||
rVol(0xffff),
|
||||
outRVol(0xffff),
|
||||
resLVol(0xffff),
|
||||
resRVol(0xffff) {}
|
||||
|
@ -150,7 +182,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf {
|
|||
virtual int getRegisterPoolSize() override;
|
||||
virtual void reset() override;
|
||||
virtual void forceIns() override;
|
||||
virtual void tick() override;
|
||||
virtual void tick(bool sysTick=true) override;
|
||||
virtual void muteChannel(int ch, bool mute) override;
|
||||
virtual bool isStereo() override;
|
||||
virtual bool keyOffAffectsArp(int ch) override;
|
||||
|
|
|
@ -97,7 +97,7 @@ void DivPlatformFDS::updateWave() {
|
|||
rWrite(0x4089,0);
|
||||
}
|
||||
|
||||
void DivPlatformFDS::tick() {
|
||||
void DivPlatformFDS::tick(bool sysTick) {
|
||||
for (int i=0; i<1; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
|
@ -107,15 +107,6 @@ void DivPlatformFDS::tick() {
|
|||
rWrite(0x4080,0x80|chan[i].outVol);
|
||||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (i==3) { // noise
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=chan[i].std.arp.val;
|
||||
} else {
|
||||
chan[i].baseFreq=chan[i].note+chan[i].std.arp.val;
|
||||
}
|
||||
if (chan[i].baseFreq>255) chan[i].baseFreq=255;
|
||||
if (chan[i].baseFreq<0) chan[i].baseFreq=0;
|
||||
} else {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
|
||||
|
@ -123,7 +114,6 @@ void DivPlatformFDS::tick() {
|
|||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
}
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
|
@ -155,6 +145,9 @@ void DivPlatformFDS::tick() {
|
|||
//if (!chan[i].keyOff) chan[i].keyOn=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].active) {
|
||||
if (ws.tick()) {
|
||||
updateWave();
|
||||
|
@ -205,7 +198,7 @@ void DivPlatformFDS::tick() {
|
|||
int DivPlatformFDS::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FDS);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
|
@ -365,7 +358,7 @@ 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].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_FDS));
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
|
|
|
@ -77,7 +77,7 @@ class DivPlatformFDS: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool keyOffAffectsArp(int ch);
|
||||
void setFlags(unsigned int flags);
|
||||
|
|
|
@ -146,7 +146,7 @@ static unsigned char noiseTable[256]={
|
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
void DivPlatformGB::tick() {
|
||||
void DivPlatformGB::tick(bool sysTick) {
|
||||
for (int i=0; i<4; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.arp.had) {
|
||||
|
@ -176,7 +176,7 @@ void DivPlatformGB::tick() {
|
|||
}
|
||||
if (chan[i].std.duty.had) {
|
||||
chan[i].duty=chan[i].std.duty.val;
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_GB);
|
||||
if (i!=2) {
|
||||
rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63)));
|
||||
} else {
|
||||
|
@ -192,6 +192,14 @@ void DivPlatformGB::tick() {
|
|||
if (!chan[i].keyOff) chan[i].keyOn=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.panL.had) {
|
||||
lastPan&=~(0x11<<i);
|
||||
lastPan|=((chan[i].std.panL.val&1)<<i)|((chan[i].std.panL.val&2)<<(i+3));
|
||||
rWrite(0x25,procMute());
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val==1) {
|
||||
chan[i].keyOn=true;
|
||||
|
@ -212,7 +220,7 @@ void DivPlatformGB::tick() {
|
|||
}
|
||||
}
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_GB);
|
||||
if (i==3) { // noise
|
||||
int ntPos=chan[i].baseFreq;
|
||||
if (ntPos<0) ntPos=0;
|
||||
|
@ -261,7 +269,7 @@ void DivPlatformGB::muteChannel(int ch, bool mute) {
|
|||
int DivPlatformGB::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_GB);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
if (c.chan==3) { // noise
|
||||
chan[c.chan].baseFreq=c.value;
|
||||
|
@ -298,7 +306,7 @@ int DivPlatformGB::dispatch(DivCommand c) {
|
|||
chan[c.chan].ins=c.value;
|
||||
chan[c.chan].insChanged=true;
|
||||
if (c.chan!=2) {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_GB);
|
||||
chan[c.chan].vol=ins->gb.envVol;
|
||||
if (parent->song.gbInsAffectsEnvelope) {
|
||||
rWrite(16+c.chan*5+2,((chan[c.chan].vol<<4))|(ins->gb.envLen&7)|((ins->gb.envDir&1)<<3));
|
||||
|
@ -352,7 +360,7 @@ int DivPlatformGB::dispatch(DivCommand c) {
|
|||
chan[c.chan].duty=c.value;
|
||||
if (c.chan!=2) {
|
||||
chan[c.chan].freqChanged=true;
|
||||
rWrite(16+c.chan*5+1,((chan[c.chan].duty&3)<<6)|(63-(parent->getIns(chan[c.chan].ins)->gb.soundLen&63)));
|
||||
rWrite(16+c.chan*5+1,((chan[c.chan].duty&3)<<6)|(63-(parent->getIns(chan[c.chan].ins,DIV_INS_GB)->gb.soundLen&63)));
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
|
@ -371,7 +379,7 @@ 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].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_GB));
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
|
|
|
@ -70,7 +70,7 @@ class DivPlatformGB: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool isStereo();
|
||||
void notifyInsChange(int ins);
|
||||
|
|
|
@ -222,7 +222,7 @@ void DivPlatformGenesis::acquire(short* bufL, short* bufR, size_t start, size_t
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformGenesis::tick() {
|
||||
void DivPlatformGenesis::tick(bool sysTick) {
|
||||
for (int i=0; i<6; i++) {
|
||||
if (i==2 && extMode) continue;
|
||||
chan[i].std.next();
|
||||
|
@ -260,6 +260,15 @@ void DivPlatformGenesis::tick() {
|
|||
}
|
||||
}
|
||||
|
||||
if (chan[i].std.panL.had) {
|
||||
chan[i].pan=chan[i].std.panL.val&3;
|
||||
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
|
||||
}
|
||||
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val==1) {
|
||||
chan[i].keyOn=true;
|
||||
|
@ -477,7 +486,7 @@ void DivPlatformGenesis::muteChannel(int ch, bool mute) {
|
|||
int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
if (c.chan==5) {
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
dacMode=1;
|
||||
|
|
|
@ -109,7 +109,7 @@ class DivPlatformGenesis: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool isStereo();
|
||||
void setYMFM(bool use);
|
||||
|
|
|
@ -37,7 +37,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
|||
int ordch=orderedOps[ch];
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins);
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
|
||||
if (opChan[ch].insChanged) {
|
||||
chan[2].state.alg=ins->fm.alg;
|
||||
|
@ -266,7 +266,7 @@ static int opChanOffsH[4]={
|
|||
0xad, 0xae, 0xac, 0xa6
|
||||
};
|
||||
|
||||
void DivPlatformGenesisExt::tick() {
|
||||
void DivPlatformGenesisExt::tick(bool sysTick) {
|
||||
if (extMode) {
|
||||
bool writeSomething=false;
|
||||
unsigned char writeMask=2;
|
||||
|
@ -283,7 +283,7 @@ void DivPlatformGenesisExt::tick() {
|
|||
}
|
||||
}
|
||||
|
||||
DivPlatformGenesis::tick();
|
||||
DivPlatformGenesis::tick(sysTick);
|
||||
|
||||
bool writeNoteOn=false;
|
||||
unsigned char writeMask=2;
|
||||
|
|
|
@ -41,7 +41,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
|
|||
void* getChanState(int chan);
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool keyOffAffectsArp(int ch);
|
||||
bool keyOffAffectsPorta(int ch);
|
||||
|
|
|
@ -145,7 +145,7 @@ void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len
|
|||
mikey->sampleAudio( bufL + start, bufR + start, len );
|
||||
}
|
||||
|
||||
void DivPlatformLynx::tick() {
|
||||
void DivPlatformLynx::tick(bool sysTick) {
|
||||
for (int i=0; i<4; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
|
@ -171,6 +171,24 @@ void DivPlatformLynx::tick() {
|
|||
}
|
||||
}
|
||||
|
||||
if (chan[i].std.panL.had) {
|
||||
chan[i].pan&=0x0f;
|
||||
chan[i].pan|=(chan[i].std.panL.val&15)<<4;
|
||||
}
|
||||
|
||||
if (chan[i].std.panR.had) {
|
||||
chan[i].pan&=0xf0;
|
||||
chan[i].pan|=chan[i].std.panR.val&15;
|
||||
}
|
||||
|
||||
if (chan[i].std.panL.had || chan[i].std.panR.had) {
|
||||
WRITE_ATTEN(i,chan[i].pan);
|
||||
}
|
||||
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
|
||||
if (chan[i].freqChanged) {
|
||||
if (chan[i].lfsr >= 0) {
|
||||
WRITE_LFSR(i, (chan[i].lfsr&0xff));
|
||||
|
@ -184,8 +202,8 @@ void DivPlatformLynx::tick() {
|
|||
}
|
||||
WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7));
|
||||
WRITE_BACKUP( i, chan[i].fd.backup );
|
||||
}
|
||||
else if (chan[i].std.duty.had) {
|
||||
chan[i].freqChanged=false;
|
||||
} else if (chan[i].std.duty.had) {
|
||||
chan[i].duty = chan[i].std.duty.val;
|
||||
WRITE_FEEDBACK(i, chan[i].duty.feedback);
|
||||
WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7));
|
||||
|
@ -206,7 +224,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].std.init(parent->getIns(chan[c.chan].ins));
|
||||
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY));
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
chan[c.chan].active=false;
|
||||
|
@ -223,7 +241,7 @@ int DivPlatformLynx::dispatch(DivCommand c) {
|
|||
break;
|
||||
case DIV_CMD_INSTRUMENT:
|
||||
chan[c.chan].ins=c.value;
|
||||
//chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
|
||||
//chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY));
|
||||
break;
|
||||
case DIV_CMD_VOLUME:
|
||||
if (chan[c.chan].vol!=c.value) {
|
||||
|
@ -279,7 +297,7 @@ int DivPlatformLynx::dispatch(DivCommand c) {
|
|||
break;
|
||||
case DIV_CMD_PRE_PORTA:
|
||||
if (chan[c.chan].active && c.value2) {
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY));
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
|
|
|
@ -80,7 +80,7 @@ class DivPlatformLynx: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool isStereo();
|
||||
bool keyOffAffectsArp(int ch);
|
||||
|
|
|
@ -96,7 +96,7 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformMMC5::tick() {
|
||||
void DivPlatformMMC5::tick(bool sysTick) {
|
||||
for (int i=0; i<2; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
|
@ -124,6 +124,9 @@ void DivPlatformMMC5::tick() {
|
|||
chan[i].duty=chan[i].std.duty.val;
|
||||
rWrite(0x5000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6));
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val==1) {
|
||||
chan[i].freqChanged=true;
|
||||
|
@ -175,7 +178,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
|
|||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON:
|
||||
if (c.chan==2) { // PCM
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_STD);
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
dacSample=ins->amiga.initSample;
|
||||
if (dacSample<0 || dacSample>=parent->song.sampleLen) {
|
||||
|
@ -225,7 +228,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
|
|||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
|
||||
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
|
||||
rWrite(0x5000+c.chan*4,0x30|chan[c.chan].vol|((chan[c.chan].duty&3)<<6));
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
|
@ -303,7 +306,7 @@ 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].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
|
|
|
@ -71,7 +71,7 @@ class DivPlatformMMC5: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool keyOffAffectsArp(int ch);
|
||||
float getPostAmp();
|
||||
|
|
|
@ -214,7 +214,7 @@ void DivPlatformN163::updateWaveCh(int ch) {
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformN163::tick() {
|
||||
void DivPlatformN163::tick(bool sysTick) {
|
||||
for (int i=0; i<=chanMax; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
|
@ -261,6 +261,9 @@ void DivPlatformN163::tick() {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].std.ex1.had) {
|
||||
if (chan[i].waveLen!=(chan[i].std.ex1.val&0xfc)) {
|
||||
chan[i].waveLen=chan[i].std.ex1.val&0xfc;
|
||||
|
@ -371,7 +374,7 @@ void DivPlatformN163::tick() {
|
|||
int DivPlatformN163::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_N163);
|
||||
if (chan[c.chan].insChanged) {
|
||||
chan[c.chan].wave=ins->n163.wave;
|
||||
chan[c.chan].ws.changeWave1(chan[c.chan].wave);
|
||||
|
@ -543,7 +546,7 @@ int DivPlatformN163::dispatch(DivCommand c) {
|
|||
case DIV_CMD_PRE_PORTA:
|
||||
if (chan[c.chan].active && c.value2) {
|
||||
if (parent->song.resetMacroOnPorta) {
|
||||
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
|
||||
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_N163));
|
||||
chan[c.chan].keyOn=true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ class DivPlatformN163: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
void setFlags(unsigned int flags);
|
||||
void notifyWaveChange(int wave);
|
||||
|
|
|
@ -141,7 +141,7 @@ static unsigned char noiseTable[253]={
|
|||
15
|
||||
};
|
||||
|
||||
void DivPlatformNES::tick() {
|
||||
void DivPlatformNES::tick(bool sysTick) {
|
||||
for (int i=0; i<4; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
|
@ -196,6 +196,9 @@ void DivPlatformNES::tick() {
|
|||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].sweepChanged) {
|
||||
chan[i].sweepChanged=false;
|
||||
if (i==0) {
|
||||
|
@ -269,7 +272,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
|
|||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON:
|
||||
if (c.chan==4) { // PCM
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_STD);
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
dacSample=ins->amiga.initSample;
|
||||
if (dacSample<0 || dacSample>=parent->song.sampleLen) {
|
||||
|
@ -323,7 +326,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
|
|||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
|
||||
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
|
||||
if (c.chan==2) {
|
||||
rWrite(0x4000+c.chan*4,0xff);
|
||||
} else {
|
||||
|
@ -426,7 +429,7 @@ 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].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
|
|
|
@ -72,7 +72,7 @@ class DivPlatformNES: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool keyOffAffectsArp(int ch);
|
||||
float getPostAmp();
|
||||
|
|
|
@ -228,7 +228,7 @@ void DivPlatformOPL::acquire(short* bufL, short* bufR, size_t start, size_t len)
|
|||
//}
|
||||
}
|
||||
|
||||
void DivPlatformOPL::tick() {
|
||||
void DivPlatformOPL::tick(bool sysTick) {
|
||||
for (int i=0; i<totalChans; i++) {
|
||||
int ops=(slots[3][i]!=255 && chan[i].state.ops==4 && oplType==3)?4:2;
|
||||
chan[i].std.next();
|
||||
|
@ -269,6 +269,14 @@ void DivPlatformOPL::tick() {
|
|||
}
|
||||
}
|
||||
|
||||
if (oplType==3 && chan[i].std.panL.had) {
|
||||
chan[i].pan=((chan[i].std.panL.val&1)<<1)|((chan[i].std.panL.val&2)>>1);
|
||||
}
|
||||
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val==1) {
|
||||
chan[i].keyOn=true;
|
||||
|
@ -282,7 +290,7 @@ void DivPlatformOPL::tick() {
|
|||
chan[i].state.fb=chan[i].std.fb.val;
|
||||
}
|
||||
|
||||
if (chan[i].std.alg.had || chan[i].std.fb.had) {
|
||||
if (chan[i].std.alg.had || chan[i].std.fb.had || (oplType==3 && chan[i].std.panL.had)) {
|
||||
if (isMuted[i]) {
|
||||
rWrite(chanMap[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&1)|(chan[i].state.fb<<1));
|
||||
if (ops==4) {
|
||||
|
@ -527,7 +535,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
}
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPL);
|
||||
|
||||
if (chan[c.chan].insChanged) {
|
||||
chan[c.chan].state=ins->fm;
|
||||
|
|
|
@ -104,7 +104,7 @@ class DivPlatformOPL: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool isStereo();
|
||||
void setYMFM(bool use);
|
||||
|
|
|
@ -111,7 +111,7 @@ void DivPlatformOPLL::acquire(short* bufL, short* bufR, size_t start, size_t len
|
|||
acquire_nuked(bufL,bufR,start,len);
|
||||
}
|
||||
|
||||
void DivPlatformOPLL::tick() {
|
||||
void DivPlatformOPLL::tick(bool sysTick) {
|
||||
for (int i=0; i<11; i++) {
|
||||
chan[i].std.next();
|
||||
|
||||
|
@ -145,6 +145,10 @@ void DivPlatformOPLL::tick() {
|
|||
}
|
||||
}
|
||||
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val==1) {
|
||||
chan[i].keyOn=true;
|
||||
|
@ -361,7 +365,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
|||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPLL);
|
||||
if (chan[c.chan].insChanged) {
|
||||
chan[c.chan].state=ins->fm;
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ class DivPlatformOPLL: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
void setYMFM(bool use);
|
||||
bool keyOffAffectsArp(int ch);
|
||||
|
|
|
@ -146,7 +146,7 @@ static unsigned char noiseFreq[12]={
|
|||
4,13,15,18,21,23,25,27,29,31,0,2
|
||||
};
|
||||
|
||||
void DivPlatformPCE::tick() {
|
||||
void DivPlatformPCE::tick(bool sysTick) {
|
||||
for (int i=0; i<6; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
|
@ -196,13 +196,27 @@ void DivPlatformPCE::tick() {
|
|||
if (!chan[i].keyOff) chan[i].keyOn=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.panL.had) {
|
||||
chan[i].pan&=0x0f;
|
||||
chan[i].pan|=(chan[i].std.panL.val&15)<<4;
|
||||
}
|
||||
if (chan[i].std.panR.had) {
|
||||
chan[i].pan&=0xf0;
|
||||
chan[i].pan|=chan[i].std.panR.val&15;
|
||||
}
|
||||
if (chan[i].std.panL.had || chan[i].std.panR.had) {
|
||||
chWrite(i,0x05,isMuted[i]?0:chan[i].pan);
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].active) {
|
||||
if (chan[i].ws.tick() || (chan[i].std.phaseReset.had && chan[i].std.phaseReset.val==1)) {
|
||||
updateWave(i);
|
||||
}
|
||||
}
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
//DivInstrument* ins=parent->getIns(chan[i].ins);
|
||||
//DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_PCE);
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)+chan[i].std.pitch.val;
|
||||
if (chan[i].furnaceDac) {
|
||||
double off=1.0;
|
||||
|
@ -237,7 +251,7 @@ void DivPlatformPCE::tick() {
|
|||
int DivPlatformPCE::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_PCE);
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
chan[c.chan].pcm=true;
|
||||
} else if (chan[c.chan].furnaceDac) {
|
||||
|
@ -415,7 +429,7 @@ 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].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_PCE));
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
|
|
|
@ -87,7 +87,7 @@ class DivPlatformPCE: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool isStereo();
|
||||
bool keyOffAffectsArp(int ch);
|
||||
|
|
|
@ -164,7 +164,7 @@ void DivPlatformPCSpeaker::acquire(short* bufL, short* bufR, size_t start, size_
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformPCSpeaker::tick() {
|
||||
void DivPlatformPCSpeaker::tick(bool sysTick) {
|
||||
for (int i=0; i<1; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
|
@ -186,6 +186,9 @@ void DivPlatformPCSpeaker::tick() {
|
|||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)-1+chan[i].std.pitch.val;
|
||||
if (chan[i].freq<0) chan[i].freq=0;
|
||||
|
@ -214,7 +217,7 @@ int DivPlatformPCSpeaker::dispatch(DivCommand c) {
|
|||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
|
||||
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER));
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
chan[c.chan].active=false;
|
||||
|
@ -279,7 +282,7 @@ 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].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER));
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
|
|
|
@ -77,7 +77,7 @@ class DivPlatformPCSpeaker: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool keyOffAffectsArp(int ch);
|
||||
void setFlags(unsigned int flags);
|
||||
|
|
|
@ -85,7 +85,7 @@ void DivPlatformPET::writeOutVol() {
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformPET::tick() {
|
||||
void DivPlatformPET::tick(bool sysTick) {
|
||||
chan.std.next();
|
||||
if (chan.std.vol.had) {
|
||||
chan.outVol=chan.std.vol.val&chan.vol;
|
||||
|
@ -112,6 +112,9 @@ void DivPlatformPET::tick() {
|
|||
rWrite(10,chan.wave);
|
||||
}
|
||||
}
|
||||
if (chan.std.pitch.had) {
|
||||
chan.freqChanged=true;
|
||||
}
|
||||
if (chan.freqChanged || chan.keyOn || chan.keyOff) {
|
||||
chan.freq=parent->calcFreq(chan.baseFreq,chan.pitch,true)+chan.std.pitch.val;
|
||||
if (chan.freq>257) chan.freq=257;
|
||||
|
@ -135,7 +138,7 @@ void DivPlatformPET::tick() {
|
|||
int DivPlatformPET::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan.ins);
|
||||
DivInstrument* ins=parent->getIns(chan.ins,DIV_INS_PET);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan.baseFreq=NOTE_PERIODIC(c.value);
|
||||
chan.freqChanged=true;
|
||||
|
@ -210,7 +213,7 @@ int DivPlatformPET::dispatch(DivCommand c) {
|
|||
break;
|
||||
case DIV_CMD_PRE_PORTA:
|
||||
if (chan.active && c.value2) {
|
||||
if (parent->song.resetMacroOnPorta) chan.std.init(parent->getIns(chan.ins));
|
||||
if (parent->song.resetMacroOnPorta) chan.std.init(parent->getIns(chan.ins,DIV_INS_PET));
|
||||
}
|
||||
chan.inPorta=c.value;
|
||||
break;
|
||||
|
|
|
@ -65,7 +65,7 @@ class DivPlatformPET: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
void notifyInsDeletion(void* ins);
|
||||
bool isStereo();
|
||||
|
|
|
@ -274,7 +274,7 @@ void DivPlatformQSound::acquire(short* bufL, short* bufR, size_t start, size_t l
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformQSound::tick() {
|
||||
void DivPlatformQSound::tick(bool sysTick) {
|
||||
for (int i=0; i<16; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
|
@ -326,8 +326,11 @@ void DivPlatformQSound::tick() {
|
|||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
//DivInstrument* ins=parent->getIns(chan[i].ins);
|
||||
//DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AMIGA);
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false)+chan[i].std.pitch.val;
|
||||
if (chan[i].freq>0xffff) chan[i].freq=0xffff;
|
||||
if (chan[i].keyOn) {
|
||||
|
@ -360,7 +363,7 @@ void DivPlatformQSound::tick() {
|
|||
int DivPlatformQSound::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
|
||||
chan[c.chan].sample=ins->amiga.initSample;
|
||||
double off=1.0;
|
||||
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||
|
@ -484,7 +487,7 @@ int DivPlatformQSound::dispatch(DivCommand c) {
|
|||
}
|
||||
case DIV_CMD_PRE_PORTA:
|
||||
if (chan[c.chan].active && c.value2) {
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
|
|
|
@ -74,7 +74,7 @@ class DivPlatformQSound: public DivDispatch {
|
|||
int getRegisterPoolDepth();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool isStereo();
|
||||
bool keyOffAffectsArp(int ch);
|
||||
|
|
|
@ -132,7 +132,7 @@ inline unsigned char applyPan(unsigned char vol, unsigned char pan) {
|
|||
return ((vol*(pan>>4))/15)|(((vol*(pan&15))/15)<<4);
|
||||
}
|
||||
|
||||
void DivPlatformSAA1099::tick() {
|
||||
void DivPlatformSAA1099::tick(bool sysTick) {
|
||||
for (int i=0; i<6; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
|
@ -166,6 +166,29 @@ void DivPlatformSAA1099::tick() {
|
|||
if (chan[i].std.wave.had) {
|
||||
chan[i].psgMode=chan[i].std.wave.val&3;
|
||||
}
|
||||
if (chan[i].std.panL.had) {
|
||||
chan[i].pan&=0x0f;
|
||||
chan[i].pan|=(chan[i].std.panL.val&15)<<4;
|
||||
}
|
||||
|
||||
if (chan[i].std.panR.had) {
|
||||
chan[i].pan&=0xf0;
|
||||
chan[i].pan|=chan[i].std.panR.val&15;
|
||||
}
|
||||
if (chan[i].std.panL.had || chan[i].std.panR.had) {
|
||||
if (isMuted[i]) {
|
||||
rWrite(i,0);
|
||||
} else {
|
||||
if (chan[i].std.vol.had) {
|
||||
if (chan[i].active) rWrite(i,applyPan(chan[i].outVol&15,chan[i].pan));
|
||||
} else {
|
||||
if (chan[i].active) rWrite(i,applyPan(chan[i].vol&15,chan[i].pan));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].std.ex1.had) {
|
||||
saaEnv[i/3]=chan[i].std.ex1.val;
|
||||
rWrite(0x18+(i/3),saaEnv[i/3]);
|
||||
|
@ -226,7 +249,7 @@ void DivPlatformSAA1099::tick() {
|
|||
int DivPlatformSAA1099::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SAA1099);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
|
@ -333,7 +356,7 @@ 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].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_SAA1099));
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
|
|
|
@ -90,7 +90,7 @@ class DivPlatformSAA1099: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
void setCore(DivSAACores core);
|
||||
void setFlags(unsigned int flags);
|
||||
|
|
|
@ -76,13 +76,14 @@ void DivPlatformSegaPCM::acquire(short* bufL, short* bufR, size_t start, size_t
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformSegaPCM::tick() {
|
||||
void DivPlatformSegaPCM::tick(bool sysTick) {
|
||||
for (int i=0; i<16; i++) {
|
||||
chan[i].std.next();
|
||||
|
||||
if (chan[i].std.vol.had) {
|
||||
// TODO: fix
|
||||
/*if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
|
||||
}
|
||||
}*/
|
||||
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
|
@ -99,6 +100,24 @@ void DivPlatformSegaPCM::tick() {
|
|||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].std.panL.had) {
|
||||
chan[i].chVolL=chan[i].std.panL.val&127;
|
||||
if (dumpWrites) {
|
||||
addWrite(0x10002+(i<<3),chan[i].chVolL);
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].std.panR.had) {
|
||||
chan[i].chVolR=chan[i].std.panR.val&127;
|
||||
if (dumpWrites) {
|
||||
addWrite(0x10003+(i<<3),chan[i].chVolR);
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
/*if (chan[i].keyOn || chan[i].keyOff) {
|
||||
chan[i].keyOff=false;
|
||||
}*/
|
||||
|
@ -130,7 +149,7 @@ void DivPlatformSegaPCM::muteChannel(int ch, bool mute) {
|
|||
int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
|
||||
if (skipRegisterWrites) break;
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
chan[c.chan].pcm.sample=ins->amiga.initSample;
|
||||
|
@ -139,14 +158,17 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
|||
if (dumpWrites) {
|
||||
addWrite(0x10086+(c.chan<<3),3);
|
||||
}
|
||||
chan[c.chan].std.init(NULL);
|
||||
break;
|
||||
}
|
||||
chan[c.chan].pcm.pos=0;
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].baseFreq=(c.value<<6);
|
||||
chan[c.chan].freqChanged=true;
|
||||
}
|
||||
chan[c.chan].furnacePCM=true;
|
||||
chan[c.chan].std.init(ins);
|
||||
if (dumpWrites) { // Sega PCM writes
|
||||
DivSample* s=parent->getSample(chan[c.chan].pcm.sample);
|
||||
addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3));
|
||||
|
@ -163,6 +185,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
chan[c.chan].std.init(NULL);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].note=c.value;
|
||||
}
|
||||
|
@ -204,6 +227,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
|||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
chan[c.chan].std.init(NULL);
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF_ENV:
|
||||
chan[c.chan].keyOff=true;
|
||||
|
|
|
@ -78,7 +78,7 @@ class DivPlatformSegaPCM: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
void notifyInsChange(int ins);
|
||||
void setFlags(unsigned int flags);
|
||||
|
|
|
@ -23,8 +23,6 @@
|
|||
|
||||
#define rWrite(v) {if (!skipRegisterWrites) {sn->write(v); if (dumpWrites) {addWrite(0x200,v);}}}
|
||||
|
||||
#define CHIP_DIVIDER 64
|
||||
|
||||
const char* regCheatSheetSN[]={
|
||||
"DATA", "0",
|
||||
NULL
|
||||
|
@ -53,8 +51,10 @@ int DivPlatformSMS::acquireOne() {
|
|||
return v;
|
||||
}
|
||||
|
||||
void DivPlatformSMS::tick() {
|
||||
void DivPlatformSMS::tick(bool sysTick) {
|
||||
for (int i=0; i<4; i++) {
|
||||
int CHIP_DIVIDER=64;
|
||||
if (i==3 && isRealSN) CHIP_DIVIDER=60;
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15));
|
||||
|
@ -98,6 +98,9 @@ void DivPlatformSMS::tick() {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
for (int i=0; i<3; i++) {
|
||||
if (chan[i].freqChanged) {
|
||||
|
@ -116,8 +119,7 @@ void DivPlatformSMS::tick() {
|
|||
}
|
||||
}
|
||||
if (chan[3].freqChanged || updateSNMode) {
|
||||
// seems arbitrary huh?
|
||||
chan[3].freq=parent->calcFreq(chan[3].baseFreq,chan[3].pitch-1-(isRealSN?127:0),true)+chan[3].std.pitch.val;
|
||||
chan[3].freq=parent->calcFreq(chan[3].baseFreq,chan[3].pitch,true)+chan[3].std.pitch.val;
|
||||
if (chan[3].freq>1023) chan[3].freq=1023;
|
||||
if (chan[3].actualNote>0x5d) chan[3].freq=0x01;
|
||||
if (snNoiseMode&2) { // take period from channel 3
|
||||
|
@ -161,6 +163,8 @@ void DivPlatformSMS::tick() {
|
|||
}
|
||||
|
||||
int DivPlatformSMS::dispatch(DivCommand c) {
|
||||
int CHIP_DIVIDER=64;
|
||||
if (c.chan==3 && isRealSN) CHIP_DIVIDER=60;
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON:
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
|
@ -171,7 +175,7 @@ int DivPlatformSMS::dispatch(DivCommand c) {
|
|||
}
|
||||
chan[c.chan].active=true;
|
||||
rWrite(0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15))));
|
||||
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
|
||||
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
chan[c.chan].active=false;
|
||||
|
@ -184,7 +188,7 @@ int DivPlatformSMS::dispatch(DivCommand c) {
|
|||
break;
|
||||
case DIV_CMD_INSTRUMENT:
|
||||
chan[c.chan].ins=c.value;
|
||||
//chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
|
||||
//chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
|
||||
break;
|
||||
case DIV_CMD_VOLUME:
|
||||
if (chan[c.chan].vol!=c.value) {
|
||||
|
@ -240,7 +244,7 @@ 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].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
|
|
|
@ -63,7 +63,7 @@ class DivPlatformSMS: public DivDispatch {
|
|||
void* getChanState(int chan);
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool keyOffAffectsArp(int ch);
|
||||
bool keyOffAffectsPorta(int ch);
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace es550x
|
|||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned long long u64;
|
||||
typedef signed char s8;
|
||||
typedef signed short s16;
|
||||
typedef signed int s32;
|
||||
|
@ -250,12 +251,14 @@ protected:
|
|||
: m_integer(integer)
|
||||
, m_fraction(fraction)
|
||||
, m_total_bits(integer + fraction)
|
||||
, m_accum_mask(u32(std::min<u64>(~0, u64(u64(1) << u64(integer + fraction)) - 1)))
|
||||
, m_transwave(transwave)
|
||||
{}
|
||||
|
||||
const u8 m_integer;
|
||||
const u8 m_fraction;
|
||||
const u8 m_total_bits;
|
||||
const u32 m_accum_mask;
|
||||
const bool m_transwave;
|
||||
|
||||
void reset();
|
||||
|
|
|
@ -29,15 +29,14 @@ bool es550x_shared_core::es550x_alu_t::busy()
|
|||
bool es550x_shared_core::es550x_alu_t::tick()
|
||||
{
|
||||
if (m_cr.dir)
|
||||
{
|
||||
m_accum = bitfield(m_accum - m_fc, 0, m_total_bits);
|
||||
return ((!m_cr.lei) && (m_accum < m_start)) ? true : false;
|
||||
}
|
||||
m_accum -= m_fc;
|
||||
else
|
||||
{
|
||||
m_accum = bitfield(m_accum + m_fc, 0, m_total_bits);
|
||||
return ((!m_cr.lei) && (m_accum > m_end)) ? true : false;
|
||||
}
|
||||
m_accum += m_fc;
|
||||
|
||||
m_accum &= m_accum_mask;
|
||||
return ((!m_cr.lei)
|
||||
&& ((( m_cr.dir) && (m_accum < m_start))
|
||||
|| ((!m_cr.dir) && (m_accum > m_end)))) ? true : false;
|
||||
}
|
||||
|
||||
void es550x_shared_core::es550x_alu_t::loop_exec()
|
||||
|
|
|
@ -141,13 +141,13 @@ void DivPlatformSwan::writeOutVol(int ch) {
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformSwan::tick() {
|
||||
void DivPlatformSwan::tick(bool sysTick) {
|
||||
unsigned char sndCtrl=(pcm?0x20:0)|(sweep?0x40:0)|((noise>0)?0x80:0);
|
||||
for (int i=0; i<4; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
int env=chan[i].std.vol.val;
|
||||
if(parent->getIns(chan[i].ins)->type==DIV_INS_AMIGA) {
|
||||
if(parent->getIns(chan[i].ins,DIV_INS_SWAN)->type==DIV_INS_AMIGA) {
|
||||
env=MIN(env/4,15);
|
||||
}
|
||||
calcAndWriteOutVol(i,env);
|
||||
|
@ -173,6 +173,20 @@ void DivPlatformSwan::tick() {
|
|||
chan[i].ws.changeWave1(chan[i].wave);
|
||||
}
|
||||
}
|
||||
if (chan[i].std.panL.had) {
|
||||
chan[i].pan&=0x0f;
|
||||
chan[i].pan|=(chan[i].std.panL.val&15)<<4;
|
||||
}
|
||||
if (chan[i].std.panR.had) {
|
||||
chan[i].pan&=0xf0;
|
||||
chan[i].pan|=chan[i].std.panR.val&15;
|
||||
}
|
||||
if (chan[i].std.panL.had || chan[i].std.panR.had) {
|
||||
calcAndWriteOutVol(i,chan[i].std.vol.will?chan[i].std.vol.val:15);
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].active) {
|
||||
sndCtrl|=(1<<i);
|
||||
if (chan[i].ws.tick()) {
|
||||
|
@ -226,7 +240,7 @@ void DivPlatformSwan::tick() {
|
|||
int DivPlatformSwan::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SWAN);
|
||||
if (c.chan==1) {
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
pcm=true;
|
||||
|
@ -401,7 +415,7 @@ 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].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_SWAN));
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
|
|
|
@ -77,7 +77,7 @@ class DivPlatformSwan: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
void notifyWaveChange(int wave);
|
||||
void notifyInsDeletion(void* ins);
|
||||
|
|
|
@ -84,7 +84,7 @@ unsigned char DivPlatformTIA::dealWithFreq(unsigned char shape, int base, int pi
|
|||
return 0;
|
||||
}
|
||||
|
||||
void DivPlatformTIA::tick() {
|
||||
void DivPlatformTIA::tick(bool sysTick) {
|
||||
for (int i=0; i<2; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
|
@ -116,6 +116,9 @@ void DivPlatformTIA::tick() {
|
|||
rWrite(0x15+i,chan[i].shape);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
if (chan[i].insChanged) {
|
||||
if (!chan[i].std.wave.will) {
|
||||
|
@ -151,7 +154,7 @@ void DivPlatformTIA::tick() {
|
|||
int DivPlatformTIA::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_TIA);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=c.value<<8;
|
||||
chan[c.chan].freqChanged=true;
|
||||
|
@ -245,7 +248,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].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_TIA));
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
|
|
|
@ -51,7 +51,7 @@ class DivPlatformTIA: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
void setFlags(unsigned int flags);
|
||||
bool isStereo();
|
||||
|
|
|
@ -183,7 +183,7 @@ inline int hScale(int note) {
|
|||
return ((note/12)<<4)+(noteMap[note%12]);
|
||||
}
|
||||
|
||||
void DivPlatformTX81Z::tick() {
|
||||
void DivPlatformTX81Z::tick(bool sysTick) {
|
||||
for (int i=0; i<8; i++) {
|
||||
chan[i].std.next();
|
||||
|
||||
|
@ -228,6 +228,10 @@ void DivPlatformTX81Z::tick() {
|
|||
rWrite(0x1b,chan[i].std.wave.val&3);
|
||||
}
|
||||
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val==1) {
|
||||
chan[i].keyOn=true;
|
||||
|
@ -420,7 +424,7 @@ void DivPlatformTX81Z::muteChannel(int ch, bool mute) {
|
|||
int DivPlatformTX81Z::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPZ);
|
||||
|
||||
if (chan[c.chan].insChanged) {
|
||||
chan[c.chan].state=ins->fm;
|
||||
|
|
|
@ -102,7 +102,7 @@ class DivPlatformTX81Z: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
void notifyInsChange(int ins);
|
||||
void setFlags(unsigned int flags);
|
||||
|
|
|
@ -114,8 +114,8 @@ void DivPlatformVERA::acquire(short* bufL, short* bufR, size_t start, size_t len
|
|||
psg_render(psg,buf[0],buf[1],curLen);
|
||||
pcm_render(pcm,buf[2],buf[3],curLen);
|
||||
for (int i=0; i<curLen; i++) {
|
||||
bufL[pos]=(short)(((int)buf[0][i]+(buf[2][i]>>1))/2);
|
||||
bufR[pos]=(short)(((int)buf[1][i]+(buf[3][i]>>1))/2);
|
||||
bufL[pos]=(short)(((int)buf[0][i]+buf[2][i])/2);
|
||||
bufR[pos]=(short)(((int)buf[1][i]+buf[3][i])/2);
|
||||
pos++;
|
||||
}
|
||||
len-=curLen;
|
||||
|
@ -156,7 +156,7 @@ int DivPlatformVERA::calcNoteFreq(int ch, int note) {
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformVERA::tick() {
|
||||
void DivPlatformVERA::tick(bool sysTick) {
|
||||
for (int i=0; i<16; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
|
@ -184,6 +184,15 @@ void DivPlatformVERA::tick() {
|
|||
if (chan[i].std.wave.had) {
|
||||
rWriteHi(i,3,chan[i].std.wave.val);
|
||||
}
|
||||
if (i<16) {
|
||||
if (chan[i].std.panL.had) {
|
||||
chan[i].pan=chan[i].std.panL.val&3;
|
||||
rWriteHi(i,2,isMuted[i]?0:chan[i].pan);
|
||||
}
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].freqChanged) {
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,8)+chan[i].std.pitch.val;
|
||||
if (chan[i].freq>65535) chan[i].freq=65535;
|
||||
|
@ -228,7 +237,7 @@ int DivPlatformVERA::dispatch(DivCommand c) {
|
|||
if(c.chan<16) {
|
||||
rWriteLo(c.chan,2,chan[c.chan].vol)
|
||||
} else {
|
||||
chan[16].pcm.sample=parent->getIns(chan[16].ins)->amiga.initSample;
|
||||
chan[16].pcm.sample=parent->getIns(chan[16].ins,DIV_INS_VERA)->amiga.initSample;
|
||||
if (chan[16].pcm.sample<0 || chan[16].pcm.sample>=parent->song.sampleLen) {
|
||||
chan[16].pcm.sample=-1;
|
||||
}
|
||||
|
@ -250,7 +259,7 @@ int DivPlatformVERA::dispatch(DivCommand c) {
|
|||
chan[c.chan].note=c.value;
|
||||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
|
||||
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VERA));
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
chan[c.chan].active=false;
|
||||
|
@ -318,7 +327,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].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VERA));
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
|
@ -374,7 +383,7 @@ void DivPlatformVERA::muteChannel(int ch, bool mute) {
|
|||
}
|
||||
|
||||
float DivPlatformVERA::getPostAmp() {
|
||||
return 4.0f;
|
||||
return 8.0f;
|
||||
}
|
||||
|
||||
bool DivPlatformVERA::isStereo() {
|
||||
|
|
|
@ -63,7 +63,7 @@ class DivPlatformVERA: public DivDispatch {
|
|||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
void notifyInsDeletion(void* ins);
|
||||
float getPostAmp();
|
||||
|
|
|
@ -91,7 +91,7 @@ void DivPlatformVIC20::writeOutVol(int ch) {
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformVIC20::tick() {
|
||||
void DivPlatformVIC20::tick(bool sysTick) {
|
||||
for (int i=0; i<4; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
|
@ -119,6 +119,9 @@ void DivPlatformVIC20::tick() {
|
|||
chan[i].keyOn=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)+chan[i].std.pitch.val;
|
||||
if (i<3) {
|
||||
|
@ -155,7 +158,7 @@ void DivPlatformVIC20::tick() {
|
|||
int DivPlatformVIC20::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_VIC);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
|
@ -229,7 +232,7 @@ 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].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VIC));
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
|
|
|
@ -66,7 +66,7 @@ class DivPlatformVIC20: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
void setFlags(unsigned int flags);
|
||||
void notifyInsDeletion(void* ins);
|
||||
|
|
|
@ -135,7 +135,7 @@ void DivPlatformVRC6::acquire(short* bufL, short* bufR, size_t start, size_t len
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformVRC6::tick() {
|
||||
void DivPlatformVRC6::tick(bool sysTick) {
|
||||
for (int i=0; i<3; i++) {
|
||||
// 16 for pulse; 14 for saw
|
||||
int CHIP_DIVIDER=(i==2)?14:16;
|
||||
|
@ -178,6 +178,9 @@ void DivPlatformVRC6::tick() {
|
|||
chWrite(i,0,(chan[i].outVol&0xf)|((chan[i].duty&7)<<4));
|
||||
}
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
if (i==2) { // sawtooth
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)-1+chan[i].std.pitch.val;
|
||||
|
@ -217,7 +220,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
|
|||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON:
|
||||
if (c.chan!=2) { // pulse wave
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_VRC6);
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
chan[c.chan].pcm=true;
|
||||
} else if (chan[c.chan].furnaceDac) {
|
||||
|
@ -281,7 +284,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
|
|||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
|
||||
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VRC6));
|
||||
if (!isMuted[c.chan]) {
|
||||
if (c.chan==2) { // sawtooth
|
||||
chWrite(c.chan,0,chan[c.chan].vol);
|
||||
|
@ -377,7 +380,7 @@ 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].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VRC6));
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
|
@ -431,9 +434,9 @@ void DivPlatformVRC6::reset() {
|
|||
chan[i]=DivPlatformVRC6::Channel();
|
||||
chan[i].std.setEngine(parent);
|
||||
}
|
||||
// a poll may be necessary to decide the default
|
||||
chan[2].vol=30;
|
||||
chan[2].outVol=30;
|
||||
// HELP
|
||||
chan[2].vol=63;
|
||||
chan[2].outVol=63;
|
||||
if (dumpWrites) {
|
||||
addWrite(0xffffffff,0);
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ class DivPlatformVRC6: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool keyOffAffectsArp(int ch);
|
||||
void setFlags(unsigned int flags);
|
||||
|
|
|
@ -336,7 +336,7 @@ void DivPlatformX1_010::updateEnvelope(int ch) {
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformX1_010::tick() {
|
||||
void DivPlatformX1_010::tick(bool sysTick) {
|
||||
for (int i=0; i<16; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
|
@ -372,6 +372,19 @@ void DivPlatformX1_010::tick() {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (chan[i].std.panL.had) {
|
||||
chan[i].pan&=0x0f;
|
||||
chan[i].pan|=(chan[i].std.panL.val&15)<<4;
|
||||
chan[i].envChanged=true;
|
||||
}
|
||||
if (chan[i].std.panR.had) {
|
||||
chan[i].pan&=0xf0;
|
||||
chan[i].pan|=chan[i].std.panR.val&15;
|
||||
chan[i].envChanged=true;
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].std.ex1.had) {
|
||||
bool nextEnable=(chan[i].std.ex1.val&1);
|
||||
if (nextEnable!=(chan[i].env.flag.envEnable)) {
|
||||
|
@ -512,7 +525,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
|
|||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
chWrite(c.chan,0,0); // reset previous note
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_X1_010);
|
||||
if ((ins->type==DIV_INS_AMIGA) || chan[c.chan].pcm) {
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
chan[c.chan].furnacePCM=true;
|
||||
|
@ -690,7 +703,7 @@ 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].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_X1_010));
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
|
|
|
@ -126,7 +126,7 @@ class DivPlatformX1_010: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool isStereo();
|
||||
bool keyOffAffectsArp(int ch);
|
||||
|
|
|
@ -365,9 +365,9 @@ void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t l
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformYM2610::tick() {
|
||||
void DivPlatformYM2610::tick(bool sysTick) {
|
||||
// PSG
|
||||
ay->tick();
|
||||
ay->tick(sysTick);
|
||||
ay->flushWrites();
|
||||
for (DivRegWrite& i: ay->getRegisterWrites()) {
|
||||
immWrite(i.addr&15,i.val);
|
||||
|
@ -408,6 +408,15 @@ void DivPlatformYM2610::tick() {
|
|||
}
|
||||
}
|
||||
|
||||
if (chan[i].std.panL.had) {
|
||||
chan[i].pan=chan[i].std.panL.val&3;
|
||||
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
|
||||
}
|
||||
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val==1) {
|
||||
chan[i].keyOn=true;
|
||||
|
@ -626,7 +635,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
if (c.chan>12) { // ADPCM-B
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
chan[c.chan].furnacePCM=true;
|
||||
} else {
|
||||
|
@ -709,7 +718,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
immWrite(0x100,0x00|(1<<(c.chan-7)));
|
||||
break;
|
||||
}
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
chan[c.chan].std.init(ins);
|
||||
if (c.chan<4) {
|
||||
if (!chan[c.chan].std.vol.will) {
|
||||
|
@ -972,7 +981,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
case DIV_CMD_PRE_PORTA:
|
||||
if (c.chan>3) {
|
||||
if (chan[c.chan].active && c.value2) {
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_FM));
|
||||
}
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
|
|
|
@ -116,7 +116,7 @@ class DivPlatformYM2610: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool isStereo();
|
||||
bool keyOffAffectsArp(int ch);
|
||||
|
|
|
@ -429,9 +429,9 @@ void DivPlatformYM2610B::acquire(short* bufL, short* bufR, size_t start, size_t
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformYM2610B::tick() {
|
||||
void DivPlatformYM2610B::tick(bool sysTick) {
|
||||
// PSG
|
||||
ay->tick();
|
||||
ay->tick(sysTick);
|
||||
ay->flushWrites();
|
||||
for (DivRegWrite& i: ay->getRegisterWrites()) {
|
||||
immWrite(i.addr&15,i.val);
|
||||
|
@ -472,6 +472,15 @@ void DivPlatformYM2610B::tick() {
|
|||
}
|
||||
}
|
||||
|
||||
if (chan[i].std.panL.had) {
|
||||
chan[i].pan=chan[i].std.panL.val&3;
|
||||
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
|
||||
}
|
||||
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val==1) {
|
||||
chan[i].keyOn=true;
|
||||
|
@ -689,7 +698,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
|||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
if (c.chan>14) { // ADPCM-B
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
chan[c.chan].furnacePCM=true;
|
||||
} else {
|
||||
|
@ -772,7 +781,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
|||
immWrite(0x100,0x00|(1<<(c.chan-9)));
|
||||
break;
|
||||
}
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
chan[c.chan].std.init(ins);
|
||||
if (c.chan<6) {
|
||||
if (!chan[c.chan].std.vol.will) {
|
||||
|
@ -1035,7 +1044,7 @@ int DivPlatformYM2610B::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].std.init(parent->getIns(chan[c.chan].ins));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_FM));
|
||||
}
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
|
|
|
@ -107,7 +107,7 @@ class DivPlatformYM2610B: public DivDispatch {
|
|||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool isStereo();
|
||||
bool keyOffAffectsArp(int ch);
|
||||
|
|
|
@ -36,7 +36,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
|||
int ordch=orderedOps[ch];
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins);
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
|
||||
DivInstrumentFM::Operator op=ins->fm.op[ordch];
|
||||
|
@ -78,7 +78,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
|||
break;
|
||||
case DIV_CMD_VOLUME: {
|
||||
opChan[ch].vol=c.value;
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins);
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
|
||||
DivInstrumentFM::Operator op=ins->fm.op[ordch];
|
||||
if (isOpMuted[ch]) {
|
||||
|
@ -104,7 +104,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
|||
} else {
|
||||
opChan[ch].pan=((c.value&15)>0)|(((c.value>>4)>0)<<1);
|
||||
}
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins);
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
if (parent->song.sharedExtStat) {
|
||||
for (int i=0; i<4; i++) {
|
||||
if (ch==i) continue;
|
||||
|
@ -159,14 +159,14 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
|||
}
|
||||
case DIV_CMD_FM_MULT: { // TODO
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins);
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]];
|
||||
rWrite(baseAddr+0x30,(c.value2&15)|(dtTable[op.dt&7]<<4));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_TL: { // TODO
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins);
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
if (isOutput[ins->fm.alg][c.value]) {
|
||||
rWrite(baseAddr+0x40,127-(((127-c.value2)*(opChan[ch].vol&0x7f))/127));
|
||||
} else {
|
||||
|
@ -175,7 +175,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AR: {
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins);
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator op=ins->fm.op[i];
|
||||
|
@ -212,7 +212,7 @@ static int opChanOffsH[4]={
|
|||
0xad, 0xae, 0xac, 0xa6
|
||||
};
|
||||
|
||||
void DivPlatformYM2610BExt::tick() {
|
||||
void DivPlatformYM2610BExt::tick(bool sysTick) {
|
||||
if (extMode) {
|
||||
bool writeSomething=false;
|
||||
unsigned char writeMask=2;
|
||||
|
@ -229,7 +229,7 @@ void DivPlatformYM2610BExt::tick() {
|
|||
}
|
||||
}
|
||||
|
||||
DivPlatformYM2610B::tick();
|
||||
DivPlatformYM2610B::tick(sysTick);
|
||||
|
||||
bool writeNoteOn=false;
|
||||
unsigned char writeMask=2;
|
||||
|
@ -268,7 +268,7 @@ void DivPlatformYM2610BExt::muteChannel(int ch, bool mute) {
|
|||
isOpMuted[ch-2]=mute;
|
||||
|
||||
int ordch=orderedOps[ch-2];
|
||||
DivInstrument* ins=parent->getIns(opChan[ch-2].ins);
|
||||
DivInstrument* ins=parent->getIns(opChan[ch-2].ins,DIV_INS_FM);
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
|
||||
DivInstrumentFM::Operator op=ins->fm.op[ordch];
|
||||
if (isOpMuted[ch-2]) {
|
||||
|
|
|
@ -41,7 +41,7 @@ class DivPlatformYM2610BExt: public DivPlatformYM2610B {
|
|||
void* getChanState(int chan);
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool keyOffAffectsArp(int ch);
|
||||
void notifyInsChange(int ins);
|
||||
|
|
|
@ -36,7 +36,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
|||
int ordch=orderedOps[ch];
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins);
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[ordch];
|
||||
DivInstrumentFM::Operator op=ins->fm.op[ordch];
|
||||
|
@ -78,7 +78,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
|||
break;
|
||||
case DIV_CMD_VOLUME: {
|
||||
opChan[ch].vol=c.value;
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins);
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[ordch];
|
||||
DivInstrumentFM::Operator op=ins->fm.op[ordch];
|
||||
if (isOpMuted[ch]) {
|
||||
|
@ -104,7 +104,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
|||
} else {
|
||||
opChan[ch].pan=((c.value&15)>0)|(((c.value>>4)>0)<<1);
|
||||
}
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins);
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
if (parent->song.sharedExtStat) {
|
||||
for (int i=0; i<4; i++) {
|
||||
if (ch==i) continue;
|
||||
|
@ -159,14 +159,14 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
|||
}
|
||||
case DIV_CMD_FM_MULT: { // TODO
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins);
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]];
|
||||
rWrite(baseAddr+0x30,(c.value2&15)|(dtTable[op.dt&7]<<4));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_TL: { // TODO
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins);
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
if (isOutput[ins->fm.alg][c.value]) {
|
||||
rWrite(baseAddr+0x40,127-(((127-c.value2)*(opChan[ch].vol&0x7f))/127));
|
||||
} else {
|
||||
|
@ -175,7 +175,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AR: {
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins);
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator op=ins->fm.op[i];
|
||||
|
@ -212,7 +212,7 @@ static int opChanOffsH[4]={
|
|||
0xad, 0xae, 0xac, 0xa6
|
||||
};
|
||||
|
||||
void DivPlatformYM2610Ext::tick() {
|
||||
void DivPlatformYM2610Ext::tick(bool sysTick) {
|
||||
if (extMode) {
|
||||
bool writeSomething=false;
|
||||
unsigned char writeMask=2;
|
||||
|
@ -229,7 +229,7 @@ void DivPlatformYM2610Ext::tick() {
|
|||
}
|
||||
}
|
||||
|
||||
DivPlatformYM2610::tick();
|
||||
DivPlatformYM2610::tick(sysTick);
|
||||
|
||||
bool writeNoteOn=false;
|
||||
unsigned char writeMask=2;
|
||||
|
@ -268,7 +268,7 @@ void DivPlatformYM2610Ext::muteChannel(int ch, bool mute) {
|
|||
isOpMuted[ch-1]=mute;
|
||||
|
||||
int ordch=orderedOps[ch-1];
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins);
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[ordch];
|
||||
DivInstrumentFM::Operator op=ins->fm.op[ordch];
|
||||
if (isOpMuted[ch]) {
|
||||
|
|
|
@ -41,7 +41,7 @@ class DivPlatformYM2610Ext: public DivPlatformYM2610 {
|
|||
void* getChanState(int chan);
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool keyOffAffectsArp(int ch);
|
||||
void notifyInsChange(int ins);
|
||||
|
|
|
@ -40,7 +40,7 @@ const char* notes[12]={
|
|||
};
|
||||
|
||||
// update this when adding new commands.
|
||||
const char* cmdName[DIV_CMD_MAX]={
|
||||
const char* cmdName[]={
|
||||
"NOTE_ON",
|
||||
"NOTE_OFF",
|
||||
"NOTE_OFF_ENV",
|
||||
|
@ -144,15 +144,27 @@ const char* cmdName[DIV_CMD_MAX]={
|
|||
"N163_WAVE_LOAD",
|
||||
"N163_WAVE_LOADPOS",
|
||||
"N163_WAVE_LOADLEN",
|
||||
"N163_WAVE_LOADMODE",
|
||||
"N163_CHANNEL_LIMIT",
|
||||
"N163_GLOBAL_WAVE_LOAD",
|
||||
"N163_GLOBAL_WAVE_LOADPOS",
|
||||
"N163_GLOBAL_WAVE_LOADLEN",
|
||||
"N163_GLOBAL_WAVE_LOADMODE",
|
||||
|
||||
"ES5506_FILTER_MODE",
|
||||
"ES5506_FILTER_K1",
|
||||
"ES5506_FILTER_K2",
|
||||
"ES5506_ENVELOPE_COUNT",
|
||||
"ES5506_ENVELOPE_LVRAMP",
|
||||
"ES5506_ENVELOPE_RVRAMP",
|
||||
"ES5506_ENVELOPE_K1RAMP",
|
||||
"ES5506_ENVELOPE_K2RAMP",
|
||||
|
||||
"ALWAYS_SET_VOLUME"
|
||||
};
|
||||
|
||||
static_assert((sizeof(cmdName)/sizeof(void*))==DIV_CMD_MAX,"update cmdName!");
|
||||
|
||||
const char* formatNote(unsigned char note, unsigned char octave) {
|
||||
static char ret[4];
|
||||
if (note==100) {
|
||||
|
@ -513,19 +525,38 @@ bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effe
|
|||
break;
|
||||
case DIV_SYSTEM_ES5506:
|
||||
switch (effect) {
|
||||
case 0x10: // echo feedback
|
||||
dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_FEEDBACK,ch,effectVal));
|
||||
case 0x10: // select waveform
|
||||
dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal));
|
||||
break;
|
||||
case 0x11: // echo level
|
||||
dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_LEVEL,ch,effectVal));
|
||||
case 0x11: // filter mode
|
||||
dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_MODE,ch,effectVal&3));
|
||||
break;
|
||||
case 0x20:
|
||||
case 0x21: // envelope ECOUNT
|
||||
dispatchCmd(DivCommand(DIV_CMD_ES5506_ENVELOPE_COUNT,ch,((effect&0x01)<<8)|effectVal));
|
||||
break;
|
||||
case 0x22: // envelope LVRAMP
|
||||
dispatchCmd(DivCommand(DIV_CMD_ES5506_ENVELOPE_LVRAMP,ch,effectVal));
|
||||
break;
|
||||
case 0x23: // envelope RVRAMP
|
||||
dispatchCmd(DivCommand(DIV_CMD_ES5506_ENVELOPE_RVRAMP,ch,effectVal));
|
||||
break;
|
||||
case 0x24:
|
||||
case 0x25: // envelope K1RAMP
|
||||
dispatchCmd(DivCommand(DIV_CMD_ES5506_ENVELOPE_K1RAMP,ch,effectVal,effect&0x01));
|
||||
break;
|
||||
case 0x26:
|
||||
case 0x27: // envelope K2RAMP
|
||||
dispatchCmd(DivCommand(DIV_CMD_ES5506_ENVELOPE_K2RAMP,ch,effectVal,effect&0x01));
|
||||
break;
|
||||
default:
|
||||
if ((effect&0xf0)==0x30) {
|
||||
dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_DELAY,ch,((effect & 0x0f) << 8) | effectVal));
|
||||
dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_K1,ch,((effect&0x0f)<<8)|effectVal));
|
||||
} else if ((effect&0xf0)==0x40) {
|
||||
dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_K2,ch,((effect&0x0f)<<8)|effectVal));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -1487,19 +1518,21 @@ void DivEngine::nextRow() {
|
|||
firstTick=true;
|
||||
}
|
||||
|
||||
bool DivEngine::nextTick(bool noAccum) {
|
||||
bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
||||
bool ret=false;
|
||||
if (divider<10) divider=10;
|
||||
|
||||
if (lowLatency) {
|
||||
if (lowLatency && !skipping && !inhibitLowLat) {
|
||||
tickMult=1000/divider;
|
||||
if (tickMult<1) tickMult=1;
|
||||
} else {
|
||||
tickMult=1;
|
||||
}
|
||||
|
||||
cycles=got.rate*pow(2,MASTER_CLOCK_PREC)/(divider*tickMult);
|
||||
clockDrift+=fmod(got.rate*pow(2,MASTER_CLOCK_PREC),(double)divider);
|
||||
if (clockDrift>=divider) {
|
||||
clockDrift-=divider;
|
||||
clockDrift+=fmod(got.rate*pow(2,MASTER_CLOCK_PREC),(double)(divider*tickMult));
|
||||
if (clockDrift>=(divider*tickMult)) {
|
||||
clockDrift-=(divider*tickMult);
|
||||
cycles++;
|
||||
}
|
||||
|
||||
|
@ -1656,7 +1689,7 @@ bool DivEngine::nextTick(bool noAccum) {
|
|||
firstTick=false;
|
||||
|
||||
// system tick
|
||||
for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->tick();
|
||||
for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->tick(subticks==tickMult);
|
||||
|
||||
if (!freelance) {
|
||||
if (stepPlay!=1) {
|
||||
|
@ -1672,7 +1705,7 @@ bool DivEngine::nextTick(bool noAccum) {
|
|||
}
|
||||
}
|
||||
|
||||
if (consoleMode) fprintf(stderr,"\x1b[2K> %d:%.2d:%.2d.%.2d %.2x/%.2x:%.3d/%.3d %4dcmd/s\x1b[G",totalSeconds/3600,(totalSeconds/60)%60,totalSeconds%60,totalTicks/10000,curOrder,song.ordersLen,curRow,song.patLen,cmdsPerSecond);
|
||||
if (consoleMode && subticks<=1) fprintf(stderr,"\x1b[2K> %d:%.2d:%.2d.%.2d %.2x/%.2x:%.3d/%.3d %4dcmd/s\x1b[G",totalSeconds/3600,(totalSeconds/60)%60,totalSeconds%60,totalTicks/10000,curOrder,song.ordersLen,curRow,song.patLen,cmdsPerSecond);
|
||||
}
|
||||
|
||||
if (haltOn==DIV_HALT_TICK) halted=true;
|
||||
|
|
|
@ -595,8 +595,8 @@ bool DivSample::resampleSinc(double r) {
|
|||
result+=s[j]*t2[7-j];
|
||||
result+=s[8+j]*t1[j];
|
||||
}
|
||||
if (result<-32768) result=-32768;
|
||||
if (result>32767) result=32767;
|
||||
if (result<-128) result=-128;
|
||||
if (result>127) result=127;
|
||||
if (i>=8) {
|
||||
data8[i-8]=result;
|
||||
}
|
||||
|
|
|
@ -324,6 +324,7 @@ struct DivSong {
|
|||
bool sharedExtStat;
|
||||
bool ignoreDACModeOutsideIntendedChannel;
|
||||
bool e1e2AlsoTakePriority;
|
||||
bool newSegaPCM;
|
||||
|
||||
DivOrders orders;
|
||||
std::vector<DivInstrument*> ins;
|
||||
|
@ -334,7 +335,7 @@ struct DivSong {
|
|||
bool chanShow[DIV_MAX_CHANS];
|
||||
bool chanCollapse[DIV_MAX_CHANS];
|
||||
|
||||
DivInstrument nullIns;
|
||||
DivInstrument nullIns, nullInsOPLL, nullInsOPL;
|
||||
DivWavetable nullWave;
|
||||
DivSample nullSample;
|
||||
|
||||
|
@ -405,7 +406,8 @@ struct DivSong {
|
|||
gbInsAffectsEnvelope(true),
|
||||
sharedExtStat(true),
|
||||
ignoreDACModeOutsideIntendedChannel(false),
|
||||
e1e2AlsoTakePriority(false) {
|
||||
e1e2AlsoTakePriority(false),
|
||||
newSegaPCM(true) {
|
||||
for (int i=0; i<32; i++) {
|
||||
system[i]=DIV_SYSTEM_NULL;
|
||||
systemVol[i]=64;
|
||||
|
@ -418,6 +420,23 @@ struct DivSong {
|
|||
}
|
||||
system[0]=DIV_SYSTEM_YM2612;
|
||||
system[1]=DIV_SYSTEM_SMS;
|
||||
|
||||
nullInsOPLL.fm.opllPreset=7;
|
||||
nullInsOPLL.fm.op[1].tl=0;
|
||||
nullInsOPLL.name="This is a bug! Report!";
|
||||
|
||||
nullInsOPL.fm.alg=0;
|
||||
nullInsOPL.fm.fb=7;
|
||||
nullInsOPL.fm.op[0].dr=2;
|
||||
nullInsOPL.fm.op[0].rr=7;
|
||||
nullInsOPL.fm.op[0].tl=22;
|
||||
nullInsOPL.fm.op[0].ksl=1;
|
||||
nullInsOPL.fm.op[0].mult=3;
|
||||
nullInsOPL.fm.op[1].tl=0;
|
||||
nullInsOPL.fm.op[1].dr=3;
|
||||
nullInsOPL.fm.op[1].rr=12;
|
||||
nullInsOPL.fm.op[1].mult=1;
|
||||
nullInsOPL.name="This is a bug! Report!";
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1133,7 +1133,7 @@ const DivInstrumentType chanPrefType[48][32]={
|
|||
{DIV_INS_VIC, DIV_INS_VIC, DIV_INS_VIC, DIV_INS_VIC}, // VIC-20
|
||||
{DIV_INS_PET}, // PET
|
||||
{DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, // SNES/N163/RF5C68
|
||||
{DIV_INS_VRC6, DIV_INS_VRC6, DIV_INS_VRC6}, // VRC6
|
||||
{DIV_INS_VRC6, DIV_INS_VRC6, DIV_INS_VRC6_SAW}, // VRC6
|
||||
{DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL}, // OPLL/VRC7
|
||||
{DIV_INS_FDS}, // FDS
|
||||
{DIV_INS_STD, DIV_INS_STD, DIV_INS_AMIGA}, // MMC5
|
||||
|
|
|
@ -752,11 +752,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
bool writeDACSamples=false;
|
||||
bool writeNESSamples=false;
|
||||
bool writePCESamples=false;
|
||||
bool writeADPCM=false;
|
||||
bool writeSegaPCM=false;
|
||||
bool writeX1010=false;
|
||||
bool writeQSound=false;
|
||||
bool writeES5506=false;
|
||||
unsigned char writeADPCM=0;
|
||||
unsigned char writeSegaPCM=0;
|
||||
unsigned char writeX1010=0;
|
||||
unsigned char writeQSound=0;
|
||||
unsigned char writeES5506=0;
|
||||
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
willExport[i]=false;
|
||||
|
@ -832,10 +832,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
if (!hasSegaPCM) {
|
||||
hasSegaPCM=4000000;
|
||||
willExport[i]=true;
|
||||
writeSegaPCM=true;
|
||||
writeSegaPCM=1;
|
||||
} else if (!(hasSegaPCM&0x40000000)) {
|
||||
isSecond[i]=true;
|
||||
willExport[i]=true;
|
||||
writeSegaPCM=2;
|
||||
hasSegaPCM|=0x40000000;
|
||||
howManyChips++;
|
||||
}
|
||||
|
@ -844,10 +845,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
if (!hasX1) {
|
||||
hasX1=disCont[i].dispatch->chipClock;
|
||||
willExport[i]=true;
|
||||
writeX1010=true;
|
||||
writeX1010=1;
|
||||
} else if (!(hasX1&0x40000000)) {
|
||||
isSecond[i]=true;
|
||||
willExport[i]=true;
|
||||
writeX1010=2;
|
||||
hasX1|=0x40000000;
|
||||
howManyChips++;
|
||||
}
|
||||
|
@ -861,10 +863,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
if (!hasOPNB) {
|
||||
hasOPNB=disCont[i].dispatch->chipClock;
|
||||
willExport[i]=true;
|
||||
writeADPCM=true;
|
||||
writeADPCM=1;
|
||||
} else if (!(hasOPNB&0x40000000)) {
|
||||
isSecond[i]=true;
|
||||
willExport[i]=true;
|
||||
writeADPCM=2;
|
||||
hasOPNB|=0x40000000;
|
||||
howManyChips++;
|
||||
}
|
||||
|
@ -966,10 +969,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
// not be able to handle the 64kb sample bank trick
|
||||
hasQSound=disCont[i].dispatch->chipClock;
|
||||
willExport[i]=true;
|
||||
writeQSound=true;
|
||||
writeQSound=1;
|
||||
} else if (!(hasQSound&0x40000000)) {
|
||||
isSecond[i]=true;
|
||||
willExport[i]=false;
|
||||
writeQSound=2;
|
||||
addWarning("dual QSound is not supported by the VGM format");
|
||||
}
|
||||
break;
|
||||
|
@ -993,11 +997,12 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
// VGM identifies ES5506 if highest bit sets, otherwise ES5505
|
||||
hasES5505=0x80000000|disCont[i].dispatch->chipClock;
|
||||
willExport[i]=true;
|
||||
writeES5506=true;
|
||||
writeES5506=1;
|
||||
} else if (!(hasES5505&0x40000000)) {
|
||||
isSecond[i]=true;
|
||||
willExport[i]=false;
|
||||
hasES5505|=0xc0000000;
|
||||
writeES5506=2;
|
||||
howManyChips++;
|
||||
}
|
||||
break;
|
||||
|
@ -1253,7 +1258,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
}
|
||||
}
|
||||
|
||||
if (writeSegaPCM) {
|
||||
if (writeSegaPCM>0) {
|
||||
unsigned char* pcmMem=new unsigned char[16777216];
|
||||
|
||||
size_t memPos=0;
|
||||
|
@ -1285,71 +1290,83 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
if (memPos>=16777216) break;
|
||||
}
|
||||
|
||||
for (unsigned char i=0; i<writeSegaPCM; i++) {
|
||||
w->writeC(0x67);
|
||||
w->writeC(0x66);
|
||||
w->writeC(0x80);
|
||||
w->writeI(memPos+8);
|
||||
w->writeI((memPos+8)|(i*0x80000000));
|
||||
w->writeI(memPos);
|
||||
w->writeI(0);
|
||||
w->write(pcmMem,memPos);
|
||||
}
|
||||
|
||||
delete[] pcmMem;
|
||||
}
|
||||
|
||||
if (writeADPCM && adpcmAMemLen>0) {
|
||||
if (adpcmAMemLen>0) {
|
||||
for (unsigned char i=0; i<writeADPCM; i++) {
|
||||
w->writeC(0x67);
|
||||
w->writeC(0x66);
|
||||
w->writeC(0x82);
|
||||
w->writeI(adpcmAMemLen+8);
|
||||
w->writeI((adpcmAMemLen+8)|(i*0x80000000));
|
||||
w->writeI(adpcmAMemLen);
|
||||
w->writeI(0);
|
||||
w->write(adpcmAMem,adpcmAMemLen);
|
||||
}
|
||||
}
|
||||
|
||||
if (writeADPCM && adpcmBMemLen>0) {
|
||||
if (adpcmBMemLen>0) {
|
||||
for (unsigned char i=0; i<writeADPCM; i++) {
|
||||
w->writeC(0x67);
|
||||
w->writeC(0x66);
|
||||
w->writeC(0x83);
|
||||
w->writeI(adpcmBMemLen+8);
|
||||
w->writeI((adpcmBMemLen+8)|(i*0x80000000));
|
||||
w->writeI(adpcmBMemLen);
|
||||
w->writeI(0);
|
||||
w->write(adpcmBMem,adpcmBMemLen);
|
||||
}
|
||||
}
|
||||
|
||||
if (writeQSound && qsoundMemLen>0) {
|
||||
if (qsoundMemLen>0) {
|
||||
// always write a whole bank
|
||||
unsigned int blockSize=(qsoundMemLen+0xffff)&(~0xffff);
|
||||
if (blockSize > 0x1000000) {
|
||||
blockSize = 0x1000000;
|
||||
}
|
||||
for (unsigned char i=0; i<writeQSound; i++) {
|
||||
w->writeC(0x67);
|
||||
w->writeC(0x66);
|
||||
w->writeC(0x8F);
|
||||
w->writeI(blockSize+8);
|
||||
w->writeI((blockSize+8)|(i*0x80000000));
|
||||
w->writeI(0x1000000);
|
||||
w->writeI(0);
|
||||
w->write(qsoundMem,blockSize);
|
||||
}
|
||||
}
|
||||
|
||||
if (writeX1010 && x1_010MemLen>0) {
|
||||
if (x1_010MemLen>0) {
|
||||
for (unsigned char i=0; i<writeX1010; i++) {
|
||||
w->writeC(0x67);
|
||||
w->writeC(0x66);
|
||||
w->writeC(0x91);
|
||||
w->writeI(x1_010MemLen+8);
|
||||
w->writeI((x1_010MemLen+8)|(i*0x80000000));
|
||||
w->writeI(x1_010MemLen);
|
||||
w->writeI(0);
|
||||
w->write(x1_010Mem,x1_010MemLen);
|
||||
}
|
||||
}
|
||||
|
||||
if (writeES5506 && es5506MemLen>0) {
|
||||
if (es5506MemLen>0) {
|
||||
for (unsigned char i=0; i<writeES5506; i++) {
|
||||
w->writeC(0x67);
|
||||
w->writeC(0x66);
|
||||
w->writeC(0x8F);
|
||||
w->writeI(es5506MemLen+8);
|
||||
w->writeI((es5506MemLen+8)|(i*0x80000000));
|
||||
w->writeI(es5506MemLen);
|
||||
w->writeI(0);
|
||||
w->write(es5506Mem,es5506MemLen);
|
||||
}
|
||||
}
|
||||
|
||||
// initialize streams
|
||||
int streamID=0;
|
||||
|
@ -1447,7 +1464,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
writeLoop=true;
|
||||
}
|
||||
}
|
||||
if (nextTick() || !playing) {
|
||||
if (nextTick(false,true) || !playing) {
|
||||
done=true;
|
||||
if (!loop) {
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
|
|
|
@ -30,8 +30,11 @@ bool DivWaveSynth::activeChanged() {
|
|||
}
|
||||
|
||||
bool DivWaveSynth::tick() {
|
||||
if (--subDivCounter>0) return false;
|
||||
|
||||
bool updated=first;
|
||||
first=false;
|
||||
subDivCounter=e->tickMult;
|
||||
if (!state.enabled) return updated;
|
||||
if (width<1) return false;
|
||||
|
||||
|
@ -167,6 +170,7 @@ void DivWaveSynth::init(DivInstrument* which, int w, int h, bool insChanged) {
|
|||
pos=0;
|
||||
stage=0;
|
||||
divCounter=1+state.rateDivider;
|
||||
subDivCounter=0;
|
||||
first=true;
|
||||
|
||||
changeWave1(state.wave1);
|
||||
|
|
|
@ -28,7 +28,7 @@ class DivEngine;
|
|||
class DivWaveSynth {
|
||||
DivEngine* e;
|
||||
DivInstrumentWaveSynth state;
|
||||
int pos, stage, divCounter, width, height;
|
||||
int pos, stage, divCounter, width, height, subDivCounter;
|
||||
bool first, activeChangedB;
|
||||
unsigned char wave1[256];
|
||||
unsigned char wave2[256];
|
||||
|
@ -78,6 +78,7 @@ class DivWaveSynth {
|
|||
divCounter(0),
|
||||
width(32),
|
||||
height(31),
|
||||
subDivCounter(0),
|
||||
first(false),
|
||||
activeChangedB(false) {
|
||||
memset(wave1,0,256);
|
||||
|
|
|
@ -214,6 +214,8 @@ void FurnaceGUI::drawAbout() {
|
|||
while (aboutHue>1) aboutHue--;
|
||||
while (aboutSin>=2400) aboutSin-=2400;
|
||||
if (aboutScroll>(42*aboutCount+scrH)) aboutScroll=-20;
|
||||
|
||||
WAKE_UP;
|
||||
}
|
||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_ABOUT;
|
||||
ImGui::End();
|
||||
|
|
|
@ -166,6 +166,10 @@ void FurnaceGUI::drawCompatFlags() {
|
|||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("behavior changed in 0.6");
|
||||
}
|
||||
ImGui::Checkbox("New SegaPCM features (macros and better panning)",&e->song.newSegaPCM);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("behavior changed in 0.6");
|
||||
}
|
||||
}
|
||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_COMPAT_FLAGS;
|
||||
ImGui::End();
|
||||
|
|
|
@ -72,9 +72,12 @@ void FurnaceGUI::drawInsList() {
|
|||
ImGui::Indent();
|
||||
}
|
||||
|
||||
for (int i=0; i<(int)e->song.ins.size(); i++) {
|
||||
for (int i=-1; i<(int)e->song.ins.size(); i++) {
|
||||
String name=ICON_FA_CIRCLE_O " - None -";
|
||||
const char* insType="Bug!";
|
||||
if (i>=0) {
|
||||
DivInstrument* ins=e->song.ins[i];
|
||||
String name;
|
||||
insType=(ins->type>DIV_INS_MAX)?"Unknown":insTypes[ins->type];
|
||||
switch (ins->type) {
|
||||
case DIV_INS_FM:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_FM]);
|
||||
|
@ -193,9 +196,12 @@ void FurnaceGUI::drawInsList() {
|
|||
name=fmt::sprintf(ICON_FA_QUESTION " %.2X: %s##_INS%d",i,ins->name,i);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_TEXT]);
|
||||
}
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Selectable(name.c_str(),curIns==i)) {
|
||||
if (ImGui::Selectable(name.c_str(),(i==-1)?(curIns<0 || curIns>=e->song.insLen):(curIns==i))) {
|
||||
curIns=i;
|
||||
}
|
||||
if (settings.insFocusesPattern && patternOpen && ImGui::IsItemActivated()) {
|
||||
|
@ -203,8 +209,8 @@ void FurnaceGUI::drawInsList() {
|
|||
curIns=i;
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("%s",(ins->type>DIV_INS_MAX)?"Unknown":insTypes[ins->type]);
|
||||
if (ImGui::IsItemHovered() && i>=0) {
|
||||
ImGui::SetTooltip("%s",insType);
|
||||
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
|
||||
insEditOpen=true;
|
||||
nextWindow=GUI_WINDOW_INS_EDIT;
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "../engine/platform/x1_010.h"
|
||||
#include "../engine/platform/n163.h"
|
||||
#include "../engine/platform/vrc6.h"
|
||||
#include "../engine/platform/es5506.h"
|
||||
#include "../engine/platform/dummy.h"
|
||||
|
||||
#define GENESIS_DEBUG \
|
||||
|
@ -333,6 +334,66 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
|||
ImGui::TextColored(ch->furnaceDac?colorOn:colorOff,">> FurnaceDAC");
|
||||
break;
|
||||
}
|
||||
case DIV_SYSTEM_ES5506: {
|
||||
DivPlatformES5506::Channel* ch=(DivPlatformES5506::Channel*)data;
|
||||
ImGui::Text("> ES5506");
|
||||
ImGui::Text("* freq: %.4x",ch->freq);
|
||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||
ImGui::Text("- note: %d",ch->note);
|
||||
ImGui::Text("- wave: %d",ch->wave);
|
||||
ImGui::Text("- sample: %d",ch->sample);
|
||||
ImGui::Text("- ins: %d",ch->ins);
|
||||
ImGui::Text("* PCM:");
|
||||
ImGui::Text(" - index: %d",ch->pcm.index);
|
||||
ImGui::Text(" - freqOffs: %.6f",ch->pcm.freqOffs);
|
||||
ImGui::Text(" - bank: %.2x",ch->pcm.bank);
|
||||
ImGui::Text(" - start: %.8x",ch->pcm.start);
|
||||
ImGui::Text(" - end: %.8x",ch->pcm.end);
|
||||
ImGui::Text(" - length: %.8x",ch->pcm.length);
|
||||
ImGui::Text(" - loopStart: %.8x",ch->pcm.loopStart);
|
||||
ImGui::Text(" - loopEnd: %.8x",ch->pcm.loopEnd);
|
||||
ImGui::Text(" - loopMode: %d",ch->pcm.loopMode);
|
||||
ImGui::Text("* Filter:");
|
||||
ImGui::Text(" - Mode: %d",ch->filter.mode);
|
||||
ImGui::Text(" - K1: %.4x",ch->filter.k1);
|
||||
ImGui::Text(" - K2: %.4x",ch->filter.k2);
|
||||
ImGui::Text("* Envelope:");
|
||||
ImGui::Text(" - EnvCount: %.3x",ch->envelope.ecount);
|
||||
ImGui::Text(" - LVRamp: %d",ch->envelope.lVRamp);
|
||||
ImGui::Text(" - RVRamp: %d",ch->envelope.rVRamp);
|
||||
ImGui::Text(" - K1Ramp: %d",ch->envelope.k1Ramp);
|
||||
ImGui::Text(" - K2Ramp: %d",ch->envelope.k2Ramp);
|
||||
ImGui::Text("- vol: %.2x",ch->vol);
|
||||
ImGui::Text("- LVol: %.2x",ch->lVol);
|
||||
ImGui::Text("- RVol: %.2x",ch->rVol);
|
||||
ImGui::Text("- outVol: %.2x",ch->outVol);
|
||||
ImGui::Text("- outLVol: %.2x",ch->outLVol);
|
||||
ImGui::Text("- outRVol: %.2x",ch->outRVol);
|
||||
ImGui::Text("- ResLVol: %.2x",ch->resLVol);
|
||||
ImGui::Text("- ResRVol: %.2x",ch->resRVol);
|
||||
ImGui::TextColored(ch->active?colorOn:colorOff,">> Active");
|
||||
ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged");
|
||||
ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged");
|
||||
ImGui::TextColored(ch->volChanged?colorOn:colorOff,">> VolChanged");
|
||||
ImGui::TextColored(ch->filterChanged.mode?colorOn:colorOff,">> FilterModeChanged");
|
||||
ImGui::TextColored(ch->filterChanged.k1?colorOn:colorOff,">> FilterK1Changed");
|
||||
ImGui::TextColored(ch->filterChanged.k2?colorOn:colorOff,">> FilterK2Changed");
|
||||
ImGui::TextColored(ch->envChanged.ecount?colorOn:colorOff,">> EnvECountChanged");
|
||||
ImGui::TextColored(ch->envChanged.lVRamp?colorOn:colorOff,">> EnvLVRampChanged");
|
||||
ImGui::TextColored(ch->envChanged.rVRamp?colorOn:colorOff,">> EnvRVRampChanged");
|
||||
ImGui::TextColored(ch->envChanged.k1Ramp?colorOn:colorOff,">> EnvK1RampChanged");
|
||||
ImGui::TextColored(ch->envChanged.k2Ramp?colorOn:colorOff,">> EnvK2RampChanged");
|
||||
ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn");
|
||||
ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff");
|
||||
ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta");
|
||||
ImGui::TextColored(ch->useWave?colorOn:colorOff,">> UseWave");
|
||||
ImGui::TextColored(ch->isReverseLoop?colorOn:colorOff,">> IsReverseLoop");
|
||||
ImGui::TextColored(ch->pcm.reversed?colorOn:colorOff,">> PCMReversed");
|
||||
ImGui::TextColored(ch->envelope.k1Slow?colorOn:colorOff,">> EnvK1Slow");
|
||||
ImGui::TextColored(ch->envelope.k2Slow?colorOn:colorOff,">> EnvK2Slow");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ImGui::Text("Unknown system! Help!");
|
||||
break;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue