Merge branch 'master' into opn_volbalance
This commit is contained in:
commit
b4df0b923b
281 changed files with 3140 additions and 1639 deletions
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -58,7 +58,7 @@ bool TAMidiInRtMidi::gather() {
|
|||
if (m.type!=TA_MIDI_SYSEX && msg.size()>1) {
|
||||
memcpy(m.data,msg.data()+1,MIN(msg.size()-1,7));
|
||||
} else if (m.type==TA_MIDI_SYSEX) {
|
||||
m.sysExData.reset(new unsigned char[msg.size()]);
|
||||
m.sysExData=std::shared_ptr<unsigned char>(new unsigned char[msg.size()],std::default_delete<unsigned char[]>());
|
||||
m.sysExLen=msg.size();
|
||||
logD("got a SysEx of length %ld!",msg.size());
|
||||
memcpy(m.sysExData.get(),msg.data(),msg.size());
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
#define DIV_MAX_CHIPS 32
|
||||
#define DIV_MAX_CHANS 128
|
||||
#define DIV_MAX_PATTERNS 256
|
||||
#define DIV_MAX_CHIP_DEFS 256
|
||||
|
||||
// in-pattern
|
||||
#define DIV_MAX_ROWS 256
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -103,9 +103,8 @@ enum DivDispatchCmds {
|
|||
DIV_CMD_FM_AM_DEPTH, // (depth)
|
||||
DIV_CMD_FM_PM_DEPTH, // (depth)
|
||||
|
||||
DIV_CMD_GENESIS_LFO, // unused?
|
||||
|
||||
DIV_CMD_ARCADE_LFO, // unused?
|
||||
DIV_CMD_FM_LFO2, // (speed)
|
||||
DIV_CMD_FM_LFO2_WAVE, // (waveform)
|
||||
|
||||
DIV_CMD_STD_NOISE_FREQ, // (freq)
|
||||
DIV_CMD_STD_NOISE_MODE, // (mode)
|
||||
|
|
@ -215,6 +214,9 @@ enum DivDispatchCmds {
|
|||
|
||||
DIV_CMD_SURROUND_PANNING, // (out, val)
|
||||
|
||||
DIV_CMD_FM_AM2_DEPTH, // (depth)
|
||||
DIV_CMD_FM_PM2_DEPTH, // (depth)
|
||||
|
||||
DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol
|
||||
|
||||
DIV_CMD_MAX
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -60,7 +60,7 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
|
|||
case 0x08:
|
||||
return "08xy: Set panning (x: left; y: right)";
|
||||
case 0x09:
|
||||
return "09xx: Set speed 1";
|
||||
return "09xx: Set groove pattern (speed 1 if no grooves exist)";
|
||||
case 0x0a:
|
||||
return "0Axy: Volume slide (0y: down; x0: up)";
|
||||
case 0x0b:
|
||||
|
|
@ -70,7 +70,7 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
|
|||
case 0x0d:
|
||||
return "0Dxx: Jump to next pattern";
|
||||
case 0x0f:
|
||||
return "0Fxx: Set speed 2";
|
||||
return "0Fxx: Set speed (speed 2 if no grooves exist)";
|
||||
case 0x80:
|
||||
return "80xx: Set panning (00: left; 80: center; FF: right)";
|
||||
case 0x81:
|
||||
|
|
@ -110,8 +110,6 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
|
|||
return "EDxx: Note delay";
|
||||
case 0xee:
|
||||
return "EExx: Send external command";
|
||||
case 0xef:
|
||||
return "EFxx: Set global tuning (quirky!)";
|
||||
case 0xf0:
|
||||
return "F0xx: Set tick rate (bpm)";
|
||||
case 0xf1:
|
||||
|
|
@ -1961,14 +1959,12 @@ String DivEngine::getPlaybackDebugInfo() {
|
|||
"cmdsPerSecond: %d\n"
|
||||
"globalPitch: %d\n"
|
||||
"extValue: %d\n"
|
||||
"speed1: %d\n"
|
||||
"speed2: %d\n"
|
||||
"tempoAccum: %d\n"
|
||||
"totalProcessed: %d\n"
|
||||
"bufferPos: %d\n",
|
||||
curOrder,prevOrder,curRow,prevRow,ticks,subticks,totalLoops,lastLoopPos,nextSpeed,divider,cycles,clockDrift,
|
||||
changeOrd,changePos,totalSeconds,totalTicks,totalTicksR,totalCmds,lastCmds,cmdsPerSecond,globalPitch,
|
||||
(int)extValue,(int)speed1,(int)speed2,(int)tempoAccum,(int)totalProcessed,(int)bufferPos
|
||||
(int)extValue,(int)tempoAccum,(int)totalProcessed,(int)bufferPos
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -2093,7 +2089,8 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) {
|
|||
lastLoopPos=-1;
|
||||
}
|
||||
endOfSong=false;
|
||||
speedAB=false;
|
||||
// whaaaaa?
|
||||
curSpeed=0;
|
||||
playing=true;
|
||||
skipping=true;
|
||||
memset(walked,0,8192);
|
||||
|
|
@ -2441,15 +2438,14 @@ void DivEngine::reset() {
|
|||
}
|
||||
extValue=0;
|
||||
extValuePresent=0;
|
||||
speed1=curSubSong->speed1;
|
||||
speed2=curSubSong->speed2;
|
||||
speeds=curSubSong->speeds;
|
||||
firstTick=false;
|
||||
shallStop=false;
|
||||
shallStopSched=false;
|
||||
pendingMetroTick=0;
|
||||
elapsedBars=0;
|
||||
elapsedBeats=0;
|
||||
nextSpeed=speed1;
|
||||
nextSpeed=speeds.val[0];
|
||||
divider=60;
|
||||
if (curSubSong->customTempo) {
|
||||
divider=curSubSong->hz;
|
||||
|
|
@ -2649,12 +2645,8 @@ size_t DivEngine::getCurrentSubSong() {
|
|||
return curSubSongIndex;
|
||||
}
|
||||
|
||||
unsigned char DivEngine::getSpeed1() {
|
||||
return speed1;
|
||||
}
|
||||
|
||||
unsigned char DivEngine::getSpeed2() {
|
||||
return speed2;
|
||||
const DivGroovePattern& DivEngine::getSpeeds() {
|
||||
return speeds;
|
||||
}
|
||||
|
||||
float DivEngine::getHz() {
|
||||
|
|
@ -4236,7 +4228,7 @@ void DivEngine::quitDispatch() {
|
|||
clockDrift=0;
|
||||
chans=0;
|
||||
playing=false;
|
||||
speedAB=false;
|
||||
curSpeed=0;
|
||||
endOfSong=false;
|
||||
ticks=0;
|
||||
tempoAccum=0;
|
||||
|
|
@ -4472,6 +4464,9 @@ bool DivEngine::init() {
|
|||
for (int i=0; i<64; i++) {
|
||||
vibTable[i]=127*sin(((double)i/64.0)*(2*M_PI));
|
||||
}
|
||||
for (int i=0; i<128; i++) {
|
||||
tremTable[i]=255*0.5*(1.0-cos(((double)i/128.0)*(2*M_PI)));
|
||||
}
|
||||
for (int i=0; i<4096; i++) {
|
||||
reversePitchTable[i]=round(1024.0*pow(2.0,(2048.0-(double)i)/(12.0*128.0)));
|
||||
pitchTable[i]=round(1024.0*pow(2.0,((double)i-2048.0)/(12.0*128.0)));
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -47,8 +47,8 @@
|
|||
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
||||
#define BUSY_END isBusy.unlock(); softLocked=false;
|
||||
|
||||
#define DIV_VERSION "dev136"
|
||||
#define DIV_ENGINE_VERSION 136
|
||||
#define DIV_VERSION "dev139"
|
||||
#define DIV_ENGINE_VERSION 139
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
#define DIV_VERSION_FC 0xff02
|
||||
|
|
@ -337,7 +337,6 @@ class DivEngine {
|
|||
bool playing;
|
||||
bool freelance;
|
||||
bool shallStop, shallStopSched;
|
||||
bool speedAB;
|
||||
bool endOfSong;
|
||||
bool consoleMode;
|
||||
bool extValuePresent;
|
||||
|
|
@ -359,7 +358,7 @@ class DivEngine {
|
|||
bool midiOutClock;
|
||||
int midiOutMode;
|
||||
int softLockCount;
|
||||
int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, nextSpeed, elapsedBars, elapsedBeats;
|
||||
int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, nextSpeed, elapsedBars, elapsedBeats, curSpeed;
|
||||
size_t curSubSongIndex;
|
||||
size_t bufferPos;
|
||||
double divider;
|
||||
|
|
@ -368,7 +367,7 @@ class DivEngine {
|
|||
int stepPlay;
|
||||
int changeOrd, changePos, totalSeconds, totalTicks, totalTicksR, totalCmds, lastCmds, cmdsPerSecond, globalPitch;
|
||||
unsigned char extValue, pendingMetroTick;
|
||||
unsigned char speed1, speed2;
|
||||
DivGroovePattern speeds;
|
||||
short tempoAccum;
|
||||
DivStatusView view;
|
||||
DivHaltPositions haltOn;
|
||||
|
|
@ -391,9 +390,9 @@ class DivEngine {
|
|||
std::vector<String> midiOuts;
|
||||
std::vector<DivCommand> cmdStream;
|
||||
std::vector<DivInstrumentType> possibleInsTypes;
|
||||
static DivSysDef* sysDefs[256];
|
||||
static DivSystem sysFileMapFur[256];
|
||||
static DivSystem sysFileMapDMF[256];
|
||||
static DivSysDef* sysDefs[DIV_MAX_CHIP_DEFS];
|
||||
static DivSystem sysFileMapFur[DIV_MAX_CHIP_DEFS];
|
||||
static DivSystem sysFileMapDMF[DIV_MAX_CHIP_DEFS];
|
||||
|
||||
struct SamplePreview {
|
||||
double rate;
|
||||
|
|
@ -413,6 +412,7 @@ class DivEngine {
|
|||
} sPreview;
|
||||
|
||||
short vibTable[64];
|
||||
short tremTable[128];
|
||||
int reversePitchTable[4096];
|
||||
int pitchTable[4096];
|
||||
char c163NameCS[1024];
|
||||
|
|
@ -442,7 +442,7 @@ class DivEngine {
|
|||
void processRow(int i, bool afterDelay);
|
||||
void nextOrder();
|
||||
void nextRow();
|
||||
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, bool directStream);
|
||||
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, bool directStream);
|
||||
// returns true if end of song.
|
||||
bool nextTick(bool noAccum=false, bool inhibitLowLat=false);
|
||||
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
|
||||
|
|
@ -729,11 +729,8 @@ class DivEngine {
|
|||
// get current subsong
|
||||
size_t getCurrentSubSong();
|
||||
|
||||
// get speed 1
|
||||
unsigned char getSpeed1();
|
||||
|
||||
// get speed 2
|
||||
unsigned char getSpeed2();
|
||||
// get speeds
|
||||
const DivGroovePattern& getSpeeds();
|
||||
|
||||
// get Hz
|
||||
float getHz();
|
||||
|
|
@ -1064,7 +1061,6 @@ class DivEngine {
|
|||
freelance(false),
|
||||
shallStop(false),
|
||||
shallStopSched(false),
|
||||
speedAB(false),
|
||||
endOfSong(false),
|
||||
consoleMode(false),
|
||||
extValuePresent(false),
|
||||
|
|
@ -1098,6 +1094,7 @@ class DivEngine {
|
|||
nextSpeed(3),
|
||||
elapsedBars(0),
|
||||
elapsedBeats(0),
|
||||
curSpeed(0),
|
||||
curSubSongIndex(0),
|
||||
bufferPos(0),
|
||||
divider(60),
|
||||
|
|
@ -1115,8 +1112,6 @@ class DivEngine {
|
|||
globalPitch(0),
|
||||
extValue(0),
|
||||
pendingMetroTick(0),
|
||||
speed1(3),
|
||||
speed2(3),
|
||||
tempoAccum(0),
|
||||
view(DIV_STATUS_NOTHING),
|
||||
haltOn(DIV_HALT_NONE),
|
||||
|
|
@ -1158,13 +1153,14 @@ class DivEngine {
|
|||
memset(dispatchOfChan,0,DIV_MAX_CHANS*sizeof(int));
|
||||
memset(sysOfChan,0,DIV_MAX_CHANS*sizeof(int));
|
||||
memset(vibTable,0,64*sizeof(short));
|
||||
memset(tremTable,0,128*sizeof(short));
|
||||
memset(reversePitchTable,0,4096*sizeof(int));
|
||||
memset(pitchTable,0,4096*sizeof(int));
|
||||
memset(sysDefs,0,256*sizeof(void*));
|
||||
memset(sysDefs,0,DIV_MAX_CHIP_DEFS*sizeof(void*));
|
||||
memset(walked,0,8192);
|
||||
memset(oscBuf,0,DIV_MAX_OUTPUTS*(sizeof(float*)));
|
||||
|
||||
for (int i=0; i<256; i++) {
|
||||
for (int i=0; i<DIV_MAX_CHIP_DEFS; i++) {
|
||||
sysFileMapFur[i]=DIV_SYSTEM_NULL;
|
||||
sysFileMapDMF[i]=DIV_SYSTEM_NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -83,7 +83,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
}
|
||||
ds.version=(unsigned char)reader.readC();
|
||||
logI("module version %d (0x%.2x)",ds.version,ds.version);
|
||||
if (ds.version>0x1a) {
|
||||
if (ds.version>0x1b) {
|
||||
logE("this version is not supported by Furnace yet!");
|
||||
lastError="this version is not supported by Furnace yet";
|
||||
delete[] file;
|
||||
|
|
@ -219,14 +219,15 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
}
|
||||
|
||||
ds.subsong[0]->timeBase=reader.readC();
|
||||
ds.subsong[0]->speed1=reader.readC();
|
||||
ds.subsong[0]->speeds.len=2;
|
||||
ds.subsong[0]->speeds.val[0]=reader.readC();
|
||||
if (ds.version>0x07) {
|
||||
ds.subsong[0]->speed2=reader.readC();
|
||||
ds.subsong[0]->speeds.val[1]=reader.readC();
|
||||
ds.subsong[0]->pal=reader.readC();
|
||||
ds.subsong[0]->hz=(ds.subsong[0]->pal)?60:50;
|
||||
ds.subsong[0]->customTempo=reader.readC();
|
||||
} else {
|
||||
ds.subsong[0]->speed2=ds.subsong[0]->speed1;
|
||||
ds.subsong[0]->speeds.len=1;
|
||||
}
|
||||
if (ds.version>0x0a) {
|
||||
String hz=reader.readString(3);
|
||||
|
|
@ -827,6 +828,8 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
for (int i=0; i<ds.sampleLen; i++) {
|
||||
DivSample* sample=new DivSample;
|
||||
int length=reader.readI();
|
||||
int cutStart=0;
|
||||
int cutEnd=length;
|
||||
int pitch=5;
|
||||
int vol=50;
|
||||
short* data;
|
||||
|
|
@ -866,6 +869,29 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
sample->depth=DIV_SAMPLE_DEPTH_YMZ_ADPCM;
|
||||
}
|
||||
}
|
||||
if (ds.version>=0x1a) {
|
||||
// what the hell man...
|
||||
cutStart=reader.readI();
|
||||
cutEnd=reader.readI();
|
||||
if (cutStart<0 || cutStart>length) {
|
||||
logE("cutStart is out of range! (%d)",cutStart);
|
||||
lastError="file is corrupt or unreadable at samples";
|
||||
delete[] file;
|
||||
return false;
|
||||
}
|
||||
if (cutEnd<0 || cutEnd>length) {
|
||||
logE("cutEnd is out of range! (%d)",cutEnd);
|
||||
lastError="file is corrupt or unreadable at samples";
|
||||
delete[] file;
|
||||
return false;
|
||||
}
|
||||
if (cutEnd<cutStart) {
|
||||
logE("cutEnd %d is before cutStart %d. what's going on?",cutEnd,cutStart);
|
||||
lastError="file is corrupt or unreadable at samples";
|
||||
delete[] file;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (length>0) {
|
||||
if (ds.version>0x08) {
|
||||
if (ds.version<0x0b) {
|
||||
|
|
@ -876,6 +902,19 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
data=new short[length];
|
||||
reader.read(data,length*2);
|
||||
}
|
||||
|
||||
if (ds.version>0x1a) {
|
||||
if (cutStart!=0 || cutEnd!=length) {
|
||||
// cut data
|
||||
short* newData=new short[cutEnd-cutStart];
|
||||
memcpy(newData,&data[cutStart],(cutEnd-cutStart)*sizeof(short));
|
||||
delete[] data;
|
||||
data=newData;
|
||||
length=cutEnd-cutStart;
|
||||
cutStart=0;
|
||||
cutEnd=length;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TA_BIG_ENDIAN
|
||||
// convert to big-endian
|
||||
|
|
@ -1716,6 +1755,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
if (ds.version<130) {
|
||||
ds.oldArpStrategy=true;
|
||||
}
|
||||
if (ds.version<138) {
|
||||
ds.brokenPortaLegato=true;
|
||||
}
|
||||
ds.isDMF=false;
|
||||
|
||||
reader.readS(); // reserved
|
||||
|
|
@ -1739,8 +1781,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
reader.readI();
|
||||
|
||||
subSong->timeBase=reader.readC();
|
||||
subSong->speed1=reader.readC();
|
||||
subSong->speed2=reader.readC();
|
||||
subSong->speeds.len=2;
|
||||
subSong->speeds.val[0]=reader.readC();
|
||||
subSong->speeds.val[1]=reader.readC();
|
||||
subSong->arpLen=reader.readC();
|
||||
subSong->hz=reader.readF();
|
||||
subSong->pal=(subSong->hz>=53);
|
||||
|
|
@ -2221,6 +2264,32 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
|
||||
if (ds.version>=136) song.patchbayAuto=reader.readC();
|
||||
|
||||
if (ds.version>=138) {
|
||||
ds.brokenPortaLegato=reader.readC();
|
||||
for (int i=0; i<7; i++) {
|
||||
reader.readC();
|
||||
}
|
||||
}
|
||||
|
||||
if (ds.version>=139) {
|
||||
subSong->speeds.len=reader.readC();
|
||||
for (int i=0; i<16; i++) {
|
||||
subSong->speeds.val[i]=reader.readC();
|
||||
}
|
||||
|
||||
// grooves
|
||||
unsigned char grooveCount=reader.readC();
|
||||
for (int i=0; i<grooveCount; i++) {
|
||||
DivGroovePattern gp;
|
||||
gp.len=reader.readC();
|
||||
for (int j=0; j<16; j++) {
|
||||
gp.val[j]=reader.readC();
|
||||
}
|
||||
|
||||
ds.grooves.push_back(gp);
|
||||
}
|
||||
}
|
||||
|
||||
// read system flags
|
||||
if (ds.version>=119) {
|
||||
logD("reading chip flags...");
|
||||
|
|
@ -2279,8 +2348,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
|
||||
subSong=ds.subsong[i+1];
|
||||
subSong->timeBase=reader.readC();
|
||||
subSong->speed1=reader.readC();
|
||||
subSong->speed2=reader.readC();
|
||||
subSong->speeds.len=2;
|
||||
subSong->speeds.val[0]=reader.readC();
|
||||
subSong->speeds.val[1]=reader.readC();
|
||||
subSong->arpLen=reader.readC();
|
||||
subSong->hz=reader.readF();
|
||||
subSong->pal=(subSong->hz>=53);
|
||||
|
|
@ -2328,6 +2398,13 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
for (int i=0; i<tchans; i++) {
|
||||
subSong->chanShortName[i]=reader.readString();
|
||||
}
|
||||
|
||||
if (ds.version>=139) {
|
||||
subSong->speeds.len=reader.readC();
|
||||
for (int i=0; i<16; i++) {
|
||||
subSong->speeds.val[i]=reader.readC();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2574,6 +2651,32 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
}
|
||||
}
|
||||
|
||||
// new YM2612/SN/X1-010 volumes
|
||||
if (ds.version<137) {
|
||||
for (int i=0; i<ds.systemLen; i++) {
|
||||
switch (ds.system[i]) {
|
||||
case DIV_SYSTEM_YM2612:
|
||||
case DIV_SYSTEM_YM2612_EXT:
|
||||
case DIV_SYSTEM_YM2612_DUALPCM:
|
||||
case DIV_SYSTEM_YM2612_DUALPCM_EXT:
|
||||
case DIV_SYSTEM_YM2612_CSM:
|
||||
ds.systemVol[i]/=2.0;
|
||||
break;
|
||||
case DIV_SYSTEM_SMS:
|
||||
case DIV_SYSTEM_T6W28:
|
||||
case DIV_SYSTEM_OPLL:
|
||||
case DIV_SYSTEM_OPLL_DRUMS:
|
||||
ds.systemVol[i]/=1.5;
|
||||
break;
|
||||
case DIV_SYSTEM_X1_010:
|
||||
ds.systemVol[i]/=4.0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (active) quitDispatch();
|
||||
BUSY_BEGIN_SOFT;
|
||||
saveLock.lock();
|
||||
|
|
@ -2920,7 +3023,6 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
if (fxVal>0x20 && ds.name!="klisje paa klisje") {
|
||||
writeFxCol(0xf0,fxVal);
|
||||
} else {
|
||||
writeFxCol(0x09,fxVal);
|
||||
writeFxCol(0x0f,fxVal);
|
||||
}
|
||||
break;
|
||||
|
|
@ -3399,8 +3501,8 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
ds.subsong[0]->pal=true;
|
||||
ds.subsong[0]->customTempo=true;
|
||||
ds.subsong[0]->pat[3].effectCols=3;
|
||||
ds.subsong[0]->speed1=3;
|
||||
ds.subsong[0]->speed2=3;
|
||||
ds.subsong[0]->speeds.val[0]=3;
|
||||
ds.subsong[0]->speeds.len=1;
|
||||
|
||||
int lastIns[4];
|
||||
int lastNote[4];
|
||||
|
|
@ -3417,10 +3519,8 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
ds.subsong[0]->orders.ord[j][i]=i;
|
||||
DivPattern* p=ds.subsong[0]->pat[j].getPattern(i,true);
|
||||
if (j==3 && seq[i].speed) {
|
||||
p->data[0][6]=0x09;
|
||||
p->data[0][6]=0x0f;
|
||||
p->data[0][7]=seq[i].speed;
|
||||
p->data[0][8]=0x0f;
|
||||
p->data[0][9]=seq[i].speed;
|
||||
}
|
||||
|
||||
bool ignoreNext=false;
|
||||
|
|
@ -4307,8 +4407,9 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
w->writeI(0);
|
||||
|
||||
w->writeC(subSong->timeBase);
|
||||
w->writeC(subSong->speed1);
|
||||
w->writeC(subSong->speed2);
|
||||
// these are for compatibility
|
||||
w->writeC(subSong->speeds.val[0]);
|
||||
w->writeC((subSong->speeds.len>=2)?subSong->speeds.val[1]:subSong->speeds.val[0]);
|
||||
w->writeC(subSong->arpLen);
|
||||
w->writeF(subSong->hz);
|
||||
w->writeS(subSong->patLen);
|
||||
|
|
@ -4489,6 +4590,27 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
}
|
||||
w->writeC(song.patchbayAuto);
|
||||
|
||||
// even more compat flags
|
||||
w->writeC(song.brokenPortaLegato);
|
||||
for (int i=0; i<7; i++) {
|
||||
w->writeC(0);
|
||||
}
|
||||
|
||||
// speeds of first song
|
||||
w->writeC(subSong->speeds.len);
|
||||
for (int i=0; i<16; i++) {
|
||||
w->writeC(subSong->speeds.val[i]);
|
||||
}
|
||||
|
||||
// groove list
|
||||
w->writeC((unsigned char)song.grooves.size());
|
||||
for (const DivGroovePattern& i: song.grooves) {
|
||||
w->writeC(i.len);
|
||||
for (int j=0; j<16; j++) {
|
||||
w->writeC(i.val[j]);
|
||||
}
|
||||
}
|
||||
|
||||
blockEndSeek=w->tell();
|
||||
w->seek(blockStartSeek,SEEK_SET);
|
||||
w->writeI(blockEndSeek-blockStartSeek-4);
|
||||
|
|
@ -4503,8 +4625,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
w->writeI(0);
|
||||
|
||||
w->writeC(subSong->timeBase);
|
||||
w->writeC(subSong->speed1);
|
||||
w->writeC(subSong->speed2);
|
||||
w->writeC(subSong->speeds.val[0]);
|
||||
w->writeC((subSong->speeds.len>=2)?subSong->speeds.val[1]:subSong->speeds.val[0]);
|
||||
w->writeC(subSong->arpLen);
|
||||
w->writeF(subSong->hz);
|
||||
w->writeS(subSong->patLen);
|
||||
|
|
@ -4543,6 +4665,12 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
w->writeString(subSong->chanShortName[i],false);
|
||||
}
|
||||
|
||||
// speeds
|
||||
w->writeC(subSong->speeds.len);
|
||||
for (int i=0; i<16; i++) {
|
||||
w->writeC(subSong->speeds.val[i]);
|
||||
}
|
||||
|
||||
blockEndSeek=w->tell();
|
||||
w->seek(blockStartSeek,SEEK_SET);
|
||||
w->writeI(blockEndSeek-blockStartSeek-4);
|
||||
|
|
@ -4798,8 +4926,8 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
|||
w->writeC(curSubSong->hilightB);
|
||||
|
||||
w->writeC(curSubSong->timeBase);
|
||||
w->writeC(curSubSong->speed1);
|
||||
w->writeC(curSubSong->speed2);
|
||||
w->writeC(curSubSong->speeds.val[0]);
|
||||
w->writeC((curSubSong->speeds.len>=2)?curSubSong->speeds.val[1]:curSubSong->speeds.val[0]);
|
||||
w->writeC(curSubSong->pal);
|
||||
w->writeC(curSubSong->customTempo);
|
||||
char customHz[4];
|
||||
|
|
@ -4823,6 +4951,14 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
|||
addWarning("only the currently selected subsong will be saved");
|
||||
}
|
||||
|
||||
if (!song.grooves.empty()) {
|
||||
addWarning("grooves will not be saved");
|
||||
}
|
||||
|
||||
if (curSubSong->speeds.len>2) {
|
||||
addWarning("only the first two speeds will be effective");
|
||||
}
|
||||
|
||||
if (curSubSong->virtualTempoD!=curSubSong->virtualTempoN) {
|
||||
addWarning(".dmf format does not support virtual tempo");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -56,7 +56,7 @@ void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released, bool tic
|
|||
}
|
||||
if (delay>0) {
|
||||
delay--;
|
||||
had=false;
|
||||
if (!linger) had=false;
|
||||
return;
|
||||
}
|
||||
if (began && source.delay>0) {
|
||||
|
|
@ -523,4 +523,4 @@ DivMacroStruct* DivMacroInt::structByName(const String& name) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#undef CONSIDER
|
||||
#undef CONSIDER
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include "../dispatch.h"
|
||||
#include "../../ta-log.h"
|
||||
|
||||
void DivDispatch::acquire(short** buf, size_t len) {
|
||||
}
|
||||
|
|
@ -121,7 +122,8 @@ void DivDispatch::notifyWaveChange(int ins) {
|
|||
}
|
||||
|
||||
void DivDispatch::notifyInsDeletion(void* ins) {
|
||||
|
||||
logE("notifyInsDeletion NOT implemented!");
|
||||
abort();
|
||||
}
|
||||
|
||||
void DivDispatch::notifyPlaybackStop() {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -319,27 +319,6 @@ void DivPlatformArcade::tick(bool sysTick) {
|
|||
rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6));
|
||||
}
|
||||
}
|
||||
if (chan[i].keyOn || chan[i].keyOff) {
|
||||
if (chan[i].hardReset && chan[i].keyOn) {
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||
immWrite(baseAddr+ADDR_SL_RR,0x0f);
|
||||
immWrite(baseAddr+ADDR_TL,0x7f);
|
||||
oldWrites[baseAddr+ADDR_SL_RR]=-1;
|
||||
oldWrites[baseAddr+ADDR_TL]=-1;
|
||||
}
|
||||
}
|
||||
immWrite(0x08,i);
|
||||
if (chan[i].hardReset && chan[i].keyOn) {
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||
for (int k=0; k<9; k++) {
|
||||
immWrite(baseAddr+ADDR_SL_RR,0x0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
chan[i].keyOff=false;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<256; i++) {
|
||||
|
|
@ -349,6 +328,24 @@ void DivPlatformArcade::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
|
||||
int hardResetElapsed=0;
|
||||
bool mustHardReset=false;
|
||||
|
||||
for (int i=0; i<8; i++) {
|
||||
if (chan[i].keyOn || chan[i].keyOff) {
|
||||
immWrite(0x08,i);
|
||||
if (chan[i].hardReset && chan[i].keyOn) {
|
||||
mustHardReset=true;
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||
immWrite(baseAddr+ADDR_SL_RR,0x0f);
|
||||
hardResetElapsed++;
|
||||
}
|
||||
}
|
||||
chan[i].keyOff=false;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<8; i++) {
|
||||
if (chan[i].freqChanged) {
|
||||
chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64+chan[i].pitch2;
|
||||
|
|
@ -363,14 +360,37 @@ void DivPlatformArcade::tick(bool sysTick) {
|
|||
if (chan[i].freq>=(95<<6)) chan[i].freq=(95<<6)-1;
|
||||
immWrite(i+0x28,hScale(chan[i].freq>>6));
|
||||
immWrite(i+0x30,chan[i].freq<<2);
|
||||
hardResetElapsed+=2;
|
||||
chan[i].freqChanged=false;
|
||||
}
|
||||
if (chan[i].keyOn || chan[i].opMaskChanged) {
|
||||
if ((chan[i].keyOn || chan[i].opMaskChanged) && !chan[i].hardReset) {
|
||||
immWrite(0x08,(chan[i].opMask<<3)|i);
|
||||
hardResetElapsed++;
|
||||
chan[i].opMaskChanged=false;
|
||||
chan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
|
||||
// hard reset handling
|
||||
if (mustHardReset) {
|
||||
for (unsigned int i=hardResetElapsed; i<hardResetCycles; i++) {
|
||||
immWrite(0x1f,i&0xff);
|
||||
}
|
||||
for (int i=0; i<8; i++) {
|
||||
if ((chan[i].keyOn || chan[i].opMaskChanged) && chan[i].hardReset) {
|
||||
// restore SL/RR
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
||||
immWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
|
||||
immWrite(0x08,(chan[i].opMask<<3)|i);
|
||||
chan[i].opMaskChanged=false;
|
||||
chan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformArcade::muteChannel(int ch, bool mute) {
|
||||
|
|
@ -382,53 +402,57 @@ void DivPlatformArcade::muteChannel(int ch, bool mute) {
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformArcade::commitState(int ch, DivInstrument* ins) {
|
||||
if (chan[ch].insChanged) {
|
||||
chan[ch].state=ins->fm;
|
||||
chan[ch].opMask=
|
||||
(chan[ch].state.op[0].enable?1:0)|
|
||||
(chan[ch].state.op[2].enable?2:0)|
|
||||
(chan[ch].state.op[1].enable?4:0)|
|
||||
(chan[ch].state.op[3].enable?8:0);
|
||||
}
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
unsigned short baseAddr=chanOffs[ch]|opOffs[i];
|
||||
DivInstrumentFM::Operator op=chan[ch].state.op[i];
|
||||
if (KVS(ch,i)) {
|
||||
if (!chan[ch].active || chan[ch].insChanged) {
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,chan[ch].outVol&0x7f,127));
|
||||
}
|
||||
} else {
|
||||
if (chan[ch].insChanged) {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
}
|
||||
if (chan[ch].insChanged) {
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6));
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
}
|
||||
if (chan[ch].insChanged) {
|
||||
if (isMuted[ch]) {
|
||||
rWrite(chanOffs[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&7)|(chan[ch].state.fb<<3));
|
||||
} else {
|
||||
rWrite(chanOffs[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&7)|(chan[ch].state.fb<<3)|((chan[ch].chVolL&1)<<6)|((chan[ch].chVolR&1)<<7));
|
||||
}
|
||||
rWrite(chanOffs[ch]+ADDR_FMS_AMS,((chan[ch].state.fms&7)<<4)|(chan[ch].state.ams&3));
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformArcade::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
|
||||
if (chan[c.chan].insChanged) {
|
||||
chan[c.chan].state=ins->fm;
|
||||
chan[c.chan].opMask=
|
||||
(chan[c.chan].state.op[0].enable?1:0)|
|
||||
(chan[c.chan].state.op[2].enable?2:0)|
|
||||
(chan[c.chan].state.op[1].enable?4:0)|
|
||||
(chan[c.chan].state.op[3].enable?8:0);
|
||||
}
|
||||
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
DivInstrumentFM::Operator op=chan[c.chan].state.op[i];
|
||||
if (KVS(c.chan,i)) {
|
||||
if (!chan[c.chan].active || chan[c.chan].insChanged) {
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,chan[c.chan].outVol&0x7f,127));
|
||||
}
|
||||
} else {
|
||||
if (chan[c.chan].insChanged) {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
}
|
||||
if (chan[c.chan].insChanged) {
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6));
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
}
|
||||
if (chan[c.chan].insChanged) {
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(chanOffs[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3));
|
||||
} else {
|
||||
rWrite(chanOffs[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3)|((chan[c.chan].chVolL&1)<<6)|((chan[c.chan].chVolR&1)<<7));
|
||||
}
|
||||
rWrite(chanOffs[c.chan]+ADDR_FMS_AMS,((chan[c.chan].state.fms&7)<<4)|(chan[c.chan].state.ams&3));
|
||||
}
|
||||
commitState(c.chan,ins);
|
||||
chan[c.chan].insChanged=false;
|
||||
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
|
|
@ -521,6 +545,11 @@ int DivPlatformArcade::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
if (chan[c.chan].insChanged) {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPM);
|
||||
commitState(c.chan,ins);
|
||||
chan[c.chan].insChanged=false;
|
||||
}
|
||||
chan[c.chan].baseFreq=NOTE_LINEAR(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
|
|
@ -800,6 +829,12 @@ void DivPlatformArcade::notifyInsChange(int ins) {
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformArcade::notifyInsDeletion(void* ins) {
|
||||
for (int i=0; i<8; i++) {
|
||||
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||
}
|
||||
}
|
||||
|
||||
void* DivPlatformArcade::getChanState(int ch) {
|
||||
return &chan[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -57,6 +57,7 @@ class DivPlatformArcade: public DivPlatformOPM {
|
|||
|
||||
int octave(int freq);
|
||||
int toFreq(int freq);
|
||||
void commitState(int ch, DivInstrument* ins);
|
||||
|
||||
void acquire_nuked(short** buf, size_t len);
|
||||
void acquire_ymfm(short** buf, size_t len);
|
||||
|
|
@ -76,6 +77,7 @@ class DivPlatformArcade: public DivPlatformOPM {
|
|||
void muteChannel(int ch, bool mute);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
void notifyInsChange(int ins);
|
||||
void notifyInsDeletion(void* ins);
|
||||
void setFlags(const DivConfig& flags);
|
||||
int getOutputCount();
|
||||
void setYMFM(bool use);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -44,7 +44,7 @@ void DivPlatformBubSysWSG::acquire(short** buf, size_t len) {
|
|||
for (size_t h=0; h<len; h++) {
|
||||
signed int out=0;
|
||||
// K005289 part
|
||||
k005289.tick();
|
||||
k005289.tick(8);
|
||||
|
||||
// Wavetable part
|
||||
for (int i=0; i<2; i++) {
|
||||
|
|
@ -60,7 +60,7 @@ void DivPlatformBubSysWSG::acquire(short** buf, size_t len) {
|
|||
}
|
||||
}
|
||||
|
||||
if (++writeOscBuf>=64) writeOscBuf=0;
|
||||
if (++writeOscBuf>=8) writeOscBuf=0;
|
||||
|
||||
out<<=6; // scale output to 16 bit
|
||||
|
||||
|
|
@ -332,9 +332,9 @@ void DivPlatformBubSysWSG::notifyInsDeletion(void* ins) {
|
|||
void DivPlatformBubSysWSG::setFlags(const DivConfig& flags) {
|
||||
chipClock=COLOR_NTSC;
|
||||
CHECK_CUSTOM_CLOCK;
|
||||
rate=chipClock;
|
||||
rate=chipClock/8;
|
||||
for (int i=0; i<2; i++) {
|
||||
oscBuf[i]->rate=rate/64;
|
||||
oscBuf[i]->rate=rate/8;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -131,6 +131,10 @@ int DivPlatformDummy::dispatch(DivCommand c) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
void DivPlatformDummy::notifyInsDeletion(void* ins) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
void DivPlatformDummy::reset() {
|
||||
for (int i=0; i<chans; i++) {
|
||||
chan[i]=DivPlatformDummy::Channel();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -40,6 +40,7 @@ class DivPlatformDummy: public DivDispatch {
|
|||
void acquire(short** buf, size_t len);
|
||||
void muteChannel(int ch, bool mute);
|
||||
int dispatch(DivCommand c);
|
||||
void notifyInsDeletion(void* ins);
|
||||
void* getChanState(int chan);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
void reset();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -41,8 +41,14 @@ class DivPlatformOPM: public DivPlatformFMBase {
|
|||
0x00, 0x08, 0x10, 0x18
|
||||
};
|
||||
|
||||
unsigned char lfoValue, lfoValue2, lfoShape, lfoShape2;
|
||||
|
||||
DivPlatformOPM():
|
||||
DivPlatformFMBase() {}
|
||||
DivPlatformFMBase(),
|
||||
lfoValue(0),
|
||||
lfoValue2(0),
|
||||
lfoShape(0),
|
||||
lfoShape2(0) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -47,6 +47,8 @@ class DivPlatformFMBase: public DivDispatch {
|
|||
0,2,1,3
|
||||
};
|
||||
|
||||
const unsigned int hardResetCycles=127;
|
||||
|
||||
struct FMChannel: public SharedChannel<int> {
|
||||
DivInstrumentFM state;
|
||||
unsigned char freqH, freqL;
|
||||
|
|
@ -83,6 +85,7 @@ class DivPlatformFMBase: public DivDispatch {
|
|||
|
||||
unsigned char lastBusy;
|
||||
int delay;
|
||||
bool flushFirst;
|
||||
|
||||
unsigned char regPool[512];
|
||||
short oldWrites[512];
|
||||
|
|
@ -102,7 +105,7 @@ class DivPlatformFMBase: public DivDispatch {
|
|||
}
|
||||
}
|
||||
inline void urgentWrite(unsigned short a, unsigned char v) {
|
||||
if (!skipRegisterWrites) {
|
||||
if (!skipRegisterWrites && !flushFirst) {
|
||||
if (writes.empty()) {
|
||||
writes.push_back(QueuedWrite(a,v));
|
||||
} else if (writes.size()>16 || writes.front().addrOrVal) {
|
||||
|
|
@ -118,9 +121,11 @@ class DivPlatformFMBase: public DivDispatch {
|
|||
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
||||
DivPlatformFMBase():DivDispatch(),
|
||||
lastBusy(0),
|
||||
delay(0) {}
|
||||
DivPlatformFMBase():
|
||||
DivDispatch(),
|
||||
lastBusy(0),
|
||||
delay(0),
|
||||
flushFirst(false) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -34,7 +34,7 @@ void DivYM2612Interface::ymfm_set_timer(uint32_t tnum, int32_t duration_in_clock
|
|||
} else if (tnum==0) {
|
||||
countA=duration_in_clocks;
|
||||
}
|
||||
logV("ymfm_set_timer(%d,%d)",tnum,duration_in_clocks);
|
||||
//logV("ymfm_set_timer(%d,%d)",tnum,duration_in_clocks);
|
||||
}
|
||||
|
||||
void DivYM2612Interface::clock() {
|
||||
|
|
@ -141,23 +141,26 @@ void DivPlatformGenesis::acquire_nuked(short** buf, size_t len) {
|
|||
|
||||
os[0]=0; os[1]=0;
|
||||
for (int i=0; i<6; i++) {
|
||||
if (!writes.empty() && --delay<0) {
|
||||
delay=0;
|
||||
QueuedWrite& w=writes.front();
|
||||
if (w.addrOrVal) {
|
||||
OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val);
|
||||
//printf("write: %x = %.2x\n",w.addr,w.val);
|
||||
lastBusy=0;
|
||||
regPool[w.addr&0x1ff]=w.val;
|
||||
writes.pop_front();
|
||||
} else {
|
||||
lastBusy++;
|
||||
if (fm.write_busy==0) {
|
||||
//printf("busycounter: %d\n",lastBusy);
|
||||
OPN2_Write(&fm,0x0+((w.addr>>8)<<1),w.addr);
|
||||
w.addrOrVal=true;
|
||||
if (!writes.empty()) {
|
||||
if (--delay<0) {
|
||||
delay=0;
|
||||
QueuedWrite& w=writes.front();
|
||||
if (w.addrOrVal) {
|
||||
//logV("%.3x = %.2x",w.addr,w.val);
|
||||
OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val);
|
||||
lastBusy=0;
|
||||
regPool[w.addr&0x1ff]=w.val;
|
||||
writes.pop_front();
|
||||
} else {
|
||||
lastBusy++;
|
||||
if (fm.write_busy==0) {
|
||||
OPN2_Write(&fm,0x0+((w.addr>>8)<<1),w.addr);
|
||||
w.addrOrVal=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
flushFirst=false;
|
||||
}
|
||||
|
||||
OPN2_Clock(&fm,o); os[0]+=o[0]; os[1]+=o[1];
|
||||
|
|
@ -207,6 +210,8 @@ void DivPlatformGenesis::acquire_ymfm(short** buf, size_t len) {
|
|||
regPool[w.addr&0x1ff]=w.val;
|
||||
writes.pop_front();
|
||||
lastBusy=1;
|
||||
} else {
|
||||
flushFirst=false;
|
||||
}
|
||||
|
||||
if (ladder) {
|
||||
|
|
@ -220,6 +225,9 @@ void DivPlatformGenesis::acquire_ymfm(short** buf, size_t len) {
|
|||
//OPN2_Write(&fm,0,0);
|
||||
|
||||
for (int i=0; i<6; i++) {
|
||||
int chOut=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1))<<6;
|
||||
if (chOut<-32768) chOut=-32768;
|
||||
if (chOut>32767) chOut=32767;
|
||||
if (i==5) {
|
||||
if (fm_ymfm->debug_dac_enable()) {
|
||||
if (softPCM) {
|
||||
|
|
@ -229,10 +237,10 @@ void DivPlatformGenesis::acquire_ymfm(short** buf, size_t len) {
|
|||
oscBuf[i]->data[oscBuf[i]->needle++]=fm_ymfm->debug_dac_data()<<7;
|
||||
}
|
||||
} else {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1))<<6;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=chOut;
|
||||
}
|
||||
} else {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1))<<6;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=chOut;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -389,6 +397,10 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
chan[i].state.ams=chan[i].std.ams.val;
|
||||
rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
|
||||
}
|
||||
if (chan[i].std.ex3.had) {
|
||||
lfoValue=(chan[i].std.ex3.val>7)?0:(8|(chan[i].std.ex3.val&7));
|
||||
rWrite(0x22,lfoValue);
|
||||
}
|
||||
if (chan[i].std.ex4.had && chan[i].active) {
|
||||
chan[i].opMask=chan[i].std.ex4.val&15;
|
||||
chan[i].opMaskChanged=true;
|
||||
|
|
@ -454,31 +466,28 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
|
||||
for (int i=0; i<512; i++) {
|
||||
if (pendingWrites[i]!=oldWrites[i]) {
|
||||
if (i==0x2b && pendingWrites[i]!=0 && !parent->song.brokenDACMode) {
|
||||
if (chan[5].keyOn) chan[5].keyOn=false;
|
||||
chan[5].keyOff=true;
|
||||
}
|
||||
immWrite(i,pendingWrites[i]&0xff);
|
||||
oldWrites[i]=pendingWrites[i];
|
||||
}
|
||||
}
|
||||
|
||||
int hardResetElapsed=0;
|
||||
bool mustHardReset=false;
|
||||
|
||||
for (int i=0; i<6; i++) {
|
||||
if (i==2 && extMode) continue;
|
||||
if (chan[i].keyOn || chan[i].keyOff) {
|
||||
immWrite(0x28,0x00|konOffs[i]);
|
||||
if (chan[i].hardReset && chan[i].keyOn) {
|
||||
mustHardReset=true;
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||
immWrite(baseAddr+ADDR_SL_RR,0x0f);
|
||||
immWrite(baseAddr+ADDR_TL,0x7f);
|
||||
oldWrites[baseAddr+ADDR_SL_RR]=-1;
|
||||
oldWrites[baseAddr+ADDR_TL]=-1;
|
||||
//rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
}
|
||||
immWrite(0x28,0x00|konOffs[i]);
|
||||
if (chan[i].hardReset && chan[i].keyOn) {
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||
for (int k=0; k<5; k++) {
|
||||
immWrite(baseAddr+ADDR_SL_RR,0x0f);
|
||||
}
|
||||
hardResetElapsed++;
|
||||
}
|
||||
}
|
||||
chan[i].keyOff=false;
|
||||
|
|
@ -507,6 +516,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
if (i<6) {
|
||||
immWrite(chanOffs[i]+ADDR_FREQH,chan[i].freq>>8);
|
||||
immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff);
|
||||
hardResetElapsed+=2;
|
||||
}
|
||||
if (chan[i].furnaceDac && chan[i].dacMode) {
|
||||
double off=1.0;
|
||||
|
|
@ -525,12 +535,38 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
}
|
||||
chan[i].freqChanged=false;
|
||||
}
|
||||
if (chan[i].keyOn || chan[i].opMaskChanged) {
|
||||
if (i<6) immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]);
|
||||
if ((chan[i].keyOn || chan[i].opMaskChanged) && !chan[i].hardReset) {
|
||||
if (i<6) {
|
||||
immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]);
|
||||
hardResetElapsed++;
|
||||
}
|
||||
chan[i].opMaskChanged=false;
|
||||
chan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
|
||||
// hard reset handling
|
||||
if (mustHardReset) {
|
||||
for (unsigned int i=hardResetElapsed; i<hardResetCycles; i++) {
|
||||
immWrite(0xf0,i&0xff);
|
||||
}
|
||||
for (int i=0; i<csmChan; i++) {
|
||||
if (i==2 && extMode) continue;
|
||||
if ((chan[i].keyOn || chan[i].opMaskChanged) && chan[i].hardReset) {
|
||||
if (i<6) {
|
||||
// restore SL/RR
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
||||
immWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]);
|
||||
}
|
||||
chan[i].opMaskChanged=false;
|
||||
chan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformGenesis::muteChannel(int ch, bool mute) {
|
||||
|
|
@ -556,6 +592,47 @@ void DivPlatformGenesis::muteChannel(int ch, bool mute) {
|
|||
rWrite(chanOffs[ch]+ADDR_LRAF,(IS_REALLY_MUTED(ch)?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4));
|
||||
}
|
||||
|
||||
void DivPlatformGenesis::commitState(int ch, DivInstrument* ins) {
|
||||
if (chan[ch].insChanged) {
|
||||
chan[ch].state=ins->fm;
|
||||
chan[ch].opMask=
|
||||
(chan[ch].state.op[0].enable?1:0)|
|
||||
(chan[ch].state.op[2].enable?2:0)|
|
||||
(chan[ch].state.op[1].enable?4:0)|
|
||||
(chan[ch].state.op[3].enable?8:0);
|
||||
}
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
unsigned short baseAddr=chanOffs[ch]|opOffs[i];
|
||||
DivInstrumentFM::Operator& op=chan[ch].state.op[i];
|
||||
if (isMuted[ch]) {
|
||||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (KVS(ch,i)) {
|
||||
if (!chan[ch].active || chan[ch].insChanged) {
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,chan[ch].outVol&0x7f,127));
|
||||
}
|
||||
} else {
|
||||
if (chan[ch].insChanged) {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[ch].insChanged) {
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||
}
|
||||
}
|
||||
if (chan[ch].insChanged) {
|
||||
rWrite(chanOffs[ch]+ADDR_FB_ALG,(chan[ch].state.alg&7)|(chan[ch].state.fb<<3));
|
||||
rWrite(chanOffs[ch]+ADDR_LRAF,(IS_REALLY_MUTED(ch)?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4));
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
|
|
@ -586,7 +663,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
}
|
||||
}
|
||||
if (c.chan>=5 && chan[c.chan].dacMode) {
|
||||
if (skipRegisterWrites) break;
|
||||
//if (skipRegisterWrites) break;
|
||||
if (ins->type==DIV_INS_AMIGA) { // Furnace mode
|
||||
if (c.value!=DIV_NOTE_NULL) chan[c.chan].dacSample=ins->amiga.getSample(c.value);
|
||||
if (chan[c.chan].dacSample<0 || chan[c.chan].dacSample>=parent->song.sampleLen) {
|
||||
|
|
@ -638,49 +715,12 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
}
|
||||
if (c.chan>=6) break;
|
||||
|
||||
if (chan[c.chan].insChanged) {
|
||||
chan[c.chan].state=ins->fm;
|
||||
chan[c.chan].opMask=
|
||||
(chan[c.chan].state.op[0].enable?1:0)|
|
||||
(chan[c.chan].state.op[2].enable?2:0)|
|
||||
(chan[c.chan].state.op[1].enable?4:0)|
|
||||
(chan[c.chan].state.op[3].enable?8:0);
|
||||
}
|
||||
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (KVS(c.chan,i)) {
|
||||
if (!chan[c.chan].active || chan[c.chan].insChanged) {
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,chan[c.chan].outVol&0x7f,127));
|
||||
}
|
||||
} else {
|
||||
if (chan[c.chan].insChanged) {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[c.chan].insChanged) {
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||
}
|
||||
}
|
||||
if (chan[c.chan].insChanged) {
|
||||
rWrite(chanOffs[c.chan]+ADDR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3));
|
||||
rWrite(chanOffs[c.chan]+ADDR_LRAF,(IS_REALLY_MUTED(c.chan)?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4));
|
||||
}
|
||||
|
||||
commitState(c.chan,ins);
|
||||
chan[c.chan].insChanged=false;
|
||||
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
|
|
@ -863,6 +903,11 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
} else if (c.chan>=5 && chan[c.chan].furnaceDac && chan[c.chan].dacMode) {
|
||||
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false);
|
||||
} else {
|
||||
if (chan[c.chan].insChanged) {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
commitState(c.chan,ins);
|
||||
chan[c.chan].insChanged=false;
|
||||
}
|
||||
chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11);
|
||||
}
|
||||
chan[c.chan].note=c.value;
|
||||
|
|
@ -1117,14 +1162,20 @@ void DivPlatformGenesis::forceIns() {
|
|||
rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
|
||||
rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
|
||||
if (chan[i].active) {
|
||||
chan[i].keyOn=true;
|
||||
chan[i].freqChanged=true;
|
||||
if (i<5 || !chan[i].dacMode) {
|
||||
chan[i].keyOn=true;
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
immWrite(0x2b,0x00);
|
||||
//rWrite(0x2a,0x00);
|
||||
if (chan[5].dacMode) {
|
||||
rWrite(0x2b,0x80);
|
||||
chan[5].dacSample=-1;
|
||||
chan[6].dacSample=-1;
|
||||
}
|
||||
immWrite(0x22,lfoValue);
|
||||
flushFirst=true;
|
||||
}
|
||||
|
||||
void DivPlatformGenesis::toggleRegisterDump(bool enable) {
|
||||
|
|
@ -1151,6 +1202,10 @@ int DivPlatformGenesis::getRegisterPoolSize() {
|
|||
return 512;
|
||||
}
|
||||
|
||||
float DivPlatformGenesis::getPostAmp() {
|
||||
return 2.0f;
|
||||
}
|
||||
|
||||
void DivPlatformGenesis::reset() {
|
||||
while (!writes.empty()) writes.pop_front();
|
||||
memset(regPool,0,512);
|
||||
|
|
@ -1178,6 +1233,7 @@ void DivPlatformGenesis::reset() {
|
|||
lfoValue=8;
|
||||
softPCMTimer=0;
|
||||
extMode=false;
|
||||
flushFirst=false;
|
||||
|
||||
if (softPCM) {
|
||||
chan[5].dacMode=true;
|
||||
|
|
@ -1214,6 +1270,9 @@ void DivPlatformGenesis::notifyInsChange(int ins) {
|
|||
}
|
||||
|
||||
void DivPlatformGenesis::notifyInsDeletion(void* ins) {
|
||||
for (int i=0; i<10; i++) {
|
||||
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformGenesis::poke(unsigned int addr, unsigned short val) {
|
||||
|
|
@ -1280,6 +1339,7 @@ int DivPlatformGenesis::init(DivEngine* p, int channels, int sugRate, const DivC
|
|||
dumpWrites=false;
|
||||
ladder=false;
|
||||
skipRegisterWrites=false;
|
||||
flushFirst=false;
|
||||
for (int i=0; i<10; i++) {
|
||||
isMuted[i]=false;
|
||||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -92,6 +92,7 @@ class DivPlatformGenesis: public DivPlatformOPN {
|
|||
friend void putDispatchChan(void*,int,int);
|
||||
|
||||
inline void processDAC(int iRate);
|
||||
inline void commitState(int ch, DivInstrument* ins);
|
||||
void acquire_nuked(short** buf, size_t len);
|
||||
void acquire_ymfm(short** buf, size_t len);
|
||||
|
||||
|
|
@ -114,10 +115,11 @@ class DivPlatformGenesis: public DivPlatformOPN {
|
|||
void setYMFM(bool use);
|
||||
bool keyOffAffectsArp(int ch);
|
||||
bool keyOffAffectsPorta(int ch);
|
||||
float getPostAmp();
|
||||
void toggleRegisterDump(bool enable);
|
||||
void setFlags(const DivConfig& flags);
|
||||
void notifyInsChange(int ins);
|
||||
void notifyInsDeletion(void* ins);
|
||||
virtual void notifyInsDeletion(void* ins);
|
||||
void setSoftPCM(bool value);
|
||||
int getPortaFloor(int ch);
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -26,6 +26,44 @@
|
|||
|
||||
#define IS_REALLY_MUTED(x) (isMuted[x] && (x<5 || !softPCM || (isMuted[5] && isMuted[6])))
|
||||
|
||||
void DivPlatformGenesisExt::commitStateExt(int ch, DivInstrument* ins) {
|
||||
int ordch=orderedOps[ch];
|
||||
|
||||
if (opChan[ch].insChanged) {
|
||||
chan[2].state.alg=ins->fm.alg;
|
||||
if (ch==0 || fbAllOps) {
|
||||
chan[2].state.fb=ins->fm.fb;
|
||||
}
|
||||
chan[2].state.fms=ins->fm.fms;
|
||||
chan[2].state.ams=ins->fm.ams;
|
||||
chan[2].state.op[ordch]=ins->fm.op[ordch];
|
||||
}
|
||||
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[ordch];
|
||||
// TODO: how does this work?!
|
||||
if (isOpMuted[ch]) {
|
||||
rWrite(baseAddr+0x40,127);
|
||||
} else {
|
||||
if (opChan[ch].insChanged) {
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127));
|
||||
}
|
||||
}
|
||||
if (opChan[ch].insChanged) {
|
||||
rWrite(baseAddr+0x30,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
|
||||
rWrite(baseAddr+0x60,(op.dr&31)|(op.am<<7));
|
||||
rWrite(baseAddr+0x70,op.d2r&31);
|
||||
rWrite(baseAddr+0x80,(op.rr&15)|(op.sl<<4));
|
||||
rWrite(baseAddr+0x90,op.ssgEnv&15);
|
||||
opChan[ch].mask=op.enable;
|
||||
}
|
||||
if (opChan[ch].insChanged) { // TODO how does this work?
|
||||
rWrite(chanOffs[2]+0xb0,(chan[2].state.alg&7)|(chan[2].state.fb<<3));
|
||||
rWrite(chanOffs[2]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4));
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
||||
if (c.chan<2) {
|
||||
return DivPlatformGenesis::dispatch(c);
|
||||
|
|
@ -44,16 +82,6 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
|||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
|
||||
if (opChan[ch].insChanged) {
|
||||
chan[2].state.alg=ins->fm.alg;
|
||||
if (ch==0 || fbAllOps) {
|
||||
chan[2].state.fb=ins->fm.fb;
|
||||
}
|
||||
chan[2].state.fms=ins->fm.fms;
|
||||
chan[2].state.ams=ins->fm.ams;
|
||||
chan[2].state.op[ordch]=ins->fm.op[ordch];
|
||||
}
|
||||
|
||||
if (noExtMacros) {
|
||||
opChan[ch].macroInit(NULL);
|
||||
} else {
|
||||
|
|
@ -62,30 +90,8 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
|||
if (!opChan[ch].std.vol.will) {
|
||||
opChan[ch].outVol=opChan[ch].vol;
|
||||
}
|
||||
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[ordch];
|
||||
// TODO: how does this work?!
|
||||
if (isOpMuted[ch]) {
|
||||
rWrite(baseAddr+0x40,127);
|
||||
} else {
|
||||
if (opChan[ch].insChanged) {
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127));
|
||||
}
|
||||
}
|
||||
if (opChan[ch].insChanged) {
|
||||
rWrite(baseAddr+0x30,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
|
||||
rWrite(baseAddr+0x60,(op.dr&31)|(op.am<<7));
|
||||
rWrite(baseAddr+0x70,op.d2r&31);
|
||||
rWrite(baseAddr+0x80,(op.rr&15)|(op.sl<<4));
|
||||
rWrite(baseAddr+0x90,op.ssgEnv&15);
|
||||
opChan[ch].mask=op.enable;
|
||||
}
|
||||
if (opChan[ch].insChanged) { // TODO how does this work?
|
||||
rWrite(chanOffs[2]+0xb0,(chan[2].state.alg&7)|(chan[2].state.fb<<3));
|
||||
rWrite(chanOffs[2]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4));
|
||||
}
|
||||
|
||||
commitStateExt(ch,ins);
|
||||
opChan[ch].insChanged=false;
|
||||
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
|
|
@ -202,6 +208,11 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
case DIV_CMD_LEGATO: {
|
||||
if (opChan[ch].insChanged) {
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
commitStateExt(ch,ins);
|
||||
opChan[ch].insChanged=false;
|
||||
}
|
||||
opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11);
|
||||
opChan[ch].freqChanged=true;
|
||||
break;
|
||||
|
|
@ -578,6 +589,7 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
|
|||
if (opChan[i].freq>0x3fff) opChan[i].freq=0x3fff;
|
||||
immWrite(opChanOffsH[i],opChan[i].freq>>8);
|
||||
immWrite(opChanOffsL[i],opChan[i].freq&0xff);
|
||||
opChan[i].freqChanged=false;
|
||||
}
|
||||
writeMask|=(unsigned char)(opChan[i].mask && opChan[i].active)<<(4+i);
|
||||
if (opChan[i].keyOn) {
|
||||
|
|
@ -640,10 +652,10 @@ void DivPlatformGenesisExt::forceIns() {
|
|||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
||||
if (i==2 && extMode) { // extended channel
|
||||
if (isOpMuted[j]) {
|
||||
if (isOpMuted[orderedOps[j]]) {
|
||||
rWrite(baseAddr+0x40,127);
|
||||
} else if (KVS(i,j)) {
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[j].outVol&0x7f,127));
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[orderedOps[j]].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+0x40,op.tl);
|
||||
}
|
||||
|
|
@ -677,6 +689,8 @@ void DivPlatformGenesisExt::forceIns() {
|
|||
}
|
||||
}
|
||||
if (chan[5].dacMode) {
|
||||
chan[5].dacSample=-1;
|
||||
chan[6].dacSample=-1;
|
||||
rWrite(0x2b,0x80);
|
||||
}
|
||||
immWrite(0x22,lfoValue);
|
||||
|
|
@ -744,6 +758,13 @@ void DivPlatformGenesisExt::notifyInsChange(int ins) {
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformGenesisExt::notifyInsDeletion(void* ins) {
|
||||
DivPlatformGenesis::notifyInsDeletion(ins);
|
||||
for (int i=0; i<4; i++) {
|
||||
opChan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformGenesisExt::getPortaFloor(int ch) {
|
||||
return (ch>8)?12:0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -29,6 +29,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
|
|||
bool isOpMuted[4];
|
||||
friend void putDispatchChip(void*,int);
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
inline void commitStateExt(int ch, DivInstrument* ins);
|
||||
public:
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
|
|
@ -41,6 +42,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
|
|||
bool keyOffAffectsArp(int ch);
|
||||
bool keyOffAffectsPorta(int ch);
|
||||
void notifyInsChange(int ins);
|
||||
void notifyInsDeletion(void* ins);
|
||||
int getPortaFloor(int ch);
|
||||
void setCSMChannel(unsigned char ch);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -353,6 +353,9 @@ void DivPlatformMSM6258::notifyInsChange(int ins) {
|
|||
}
|
||||
|
||||
void DivPlatformMSM6258::notifyInsDeletion(void* ins) {
|
||||
for (int i=0; i<1; i++) {
|
||||
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformMSM6258::setFlags(const DivConfig& flags) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -326,6 +326,9 @@ void DivPlatformMSM6295::notifyInsChange(int ins) {
|
|||
}
|
||||
|
||||
void DivPlatformMSM6295::notifyInsDeletion(void* ins) {
|
||||
for (int i=0; i<4; i++) {
|
||||
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||
}
|
||||
}
|
||||
|
||||
const void* DivPlatformMSM6295::getSampleMem(int index) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -230,7 +230,7 @@ void DivPlatformNamcoWSG::tick(bool sysTick) {
|
|||
if (chan[i].std.pitch.had) {
|
||||
if (chan[i].std.pitch.mode) {
|
||||
chan[i].pitch2+=chan[i].std.pitch.val;
|
||||
CLAMP_VAR(chan[i].pitch2,-32768,32767);
|
||||
CLAMP_VAR(chan[i].pitch2,-1048575,1048575);
|
||||
} else {
|
||||
chan[i].pitch2=chan[i].std.pitch.val;
|
||||
}
|
||||
|
|
@ -244,6 +244,7 @@ void DivPlatformNamcoWSG::tick(bool sysTick) {
|
|||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
//DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_PCE);
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE);
|
||||
if (chan[i].freq<0) chan[i].freq=0;
|
||||
if (chan[i].freq>1048575) chan[i].freq=1048575;
|
||||
if (chan[i].keyOn) {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -446,35 +446,34 @@ void DivPlatformOPL::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i<melodicChans) {
|
||||
if (chan[i].hardReset && chan[i].keyOn) {
|
||||
for (int j=0; j<ops; j++) {
|
||||
unsigned char slot=slots[j][i];
|
||||
if (slot==255) continue;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
DivInstrumentFM::Operator& op=chan[i].state.op[(ops==4)?orderedOpsL[j]:j];
|
||||
immWrite(baseAddr+ADDR_SL_RR,0x0f);
|
||||
immWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
||||
oldWrites[baseAddr+ADDR_SL_RR]=-1;
|
||||
oldWrites[baseAddr+ADDR_KSL_TL]=-1;
|
||||
}
|
||||
}
|
||||
if (chan[i].keyOn || chan[i].keyOff) {
|
||||
immWrite(chanMap[i]+ADDR_FREQH,0x00|(chan[i].freqH&31));
|
||||
chan[i].keyOff=false;
|
||||
}
|
||||
if (chan[i].hardReset && chan[i].keyOn) {
|
||||
for (int j=0; j<ops; j++) {
|
||||
unsigned char slot=slots[j][i];
|
||||
if (slot==255) continue;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
DivInstrumentFM::Operator& op=chan[i].state.op[(ops==4)?orderedOpsL[j]:j];
|
||||
for (int k=0; k<5; k++) {
|
||||
immWrite(baseAddr+ADDR_SL_RR,0x0f);
|
||||
immWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
||||
}
|
||||
int hardResetElapsed=0;
|
||||
bool mustHardReset=false;
|
||||
bool weWillWriteRRLater[64];
|
||||
|
||||
memset(weWillWriteRRLater,0,64*sizeof(bool));
|
||||
|
||||
for (int i=0; i<melodicChans; i++) {
|
||||
int ops=(slots[3][i]!=255 && chan[i].state.ops==4 && oplType==3)?4:2;
|
||||
|
||||
if (chan[i].keyOn || chan[i].keyOff) {
|
||||
immWrite(chanMap[i]+ADDR_FREQH,0x00|(chan[i].freqH&31));
|
||||
chan[i].keyOff=false;
|
||||
}
|
||||
if (chan[i].hardReset && chan[i].keyOn) {
|
||||
mustHardReset=true;
|
||||
for (int j=0; j<ops; j++) {
|
||||
unsigned char slot=slots[j][i];
|
||||
if (slot==255) continue;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
if (baseAddr>0x100) {
|
||||
weWillWriteRRLater[(baseAddr&0xff)|32]=true;
|
||||
} else {
|
||||
weWillWriteRRLater[(baseAddr&0xff)]=true;
|
||||
}
|
||||
immWrite(baseAddr+ADDR_SL_RR,0x0f);
|
||||
hardResetElapsed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -562,6 +561,11 @@ void DivPlatformOPL::tick(bool sysTick) {
|
|||
|
||||
for (int i=0; i<512; i++) {
|
||||
if (pendingWrites[i]!=oldWrites[i]) {
|
||||
if ((i>=0x80 && i<0xa0)) {
|
||||
if (weWillWriteRRLater[i-0x80]) continue;
|
||||
} else if ((i>=0x180 && i<0x1a0)) {
|
||||
if (weWillWriteRRLater[32|(i-0x180)]) continue;
|
||||
}
|
||||
immWrite(i,pendingWrites[i]&0xff);
|
||||
oldWrites[i]=pendingWrites[i];
|
||||
}
|
||||
|
|
@ -580,11 +584,15 @@ void DivPlatformOPL::tick(bool sysTick) {
|
|||
immWrite(chanMap[i]+ADDR_FREQ,chan[i].freqL);
|
||||
}
|
||||
if (i<melodicChans) {
|
||||
if (chan[i].keyOn) {
|
||||
if (chan[i].keyOn && !chan[i].hardReset) {
|
||||
immWrite(chanMap[i]+ADDR_FREQH,chan[i].freqH|(0x20));
|
||||
chan[i].keyOn=false;
|
||||
} else if (chan[i].freqChanged) {
|
||||
immWrite(chanMap[i]+ADDR_FREQH,chan[i].freqH|(chan[i].active<<5));
|
||||
if (chan[i].keyOn && chan[i].hardReset) {
|
||||
immWrite(chanMap[i]+ADDR_FREQH,chan[i].freqH|0);
|
||||
} else {
|
||||
immWrite(chanMap[i]+ADDR_FREQH,chan[i].freqH|(chan[i].active<<5));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (chan[i].keyOn) {
|
||||
|
|
@ -602,6 +610,35 @@ void DivPlatformOPL::tick(bool sysTick) {
|
|||
if (updateDrums) {
|
||||
immWrite(0xbd,(dam<<7)|(dvb<<6)|(properDrums<<5)|drumState);
|
||||
}
|
||||
|
||||
// hard reset handling
|
||||
if (mustHardReset) {
|
||||
for (unsigned int i=hardResetElapsed; i<128; i++) {
|
||||
immWrite(0x3f,i&0xff);
|
||||
}
|
||||
for (int i=0x80; i<0xa0; i++) {
|
||||
if (weWillWriteRRLater[i-0x80]) {
|
||||
immWrite(i,pendingWrites[i]&0xff);
|
||||
oldWrites[i]=pendingWrites[i];
|
||||
}
|
||||
}
|
||||
for (int i=0x180; i<0x1a0; i++) {
|
||||
if (weWillWriteRRLater[32|(i-0x180)]) {
|
||||
immWrite(i,pendingWrites[i]&0xff);
|
||||
oldWrites[i]=pendingWrites[i];
|
||||
}
|
||||
}
|
||||
for (int i=0; i<melodicChans; i++) {
|
||||
if (chan[i].hardReset) {
|
||||
if (chan[i].keyOn) {
|
||||
immWrite(chanMap[i]+ADDR_FREQH,chan[i].freqH|(0x20));
|
||||
chan[i].keyOn=false;
|
||||
} else if (chan[i].freqChanged) {
|
||||
immWrite(chanMap[i]+ADDR_FREQH,chan[i].freqH|(chan[i].active<<5));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define OPLL_C_NUM 686
|
||||
|
|
@ -689,6 +726,112 @@ void DivPlatformOPL::muteChannel(int ch, bool mute) {
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformOPL::commitState(int ch, DivInstrument* ins) {
|
||||
if (chan[ch].insChanged) {
|
||||
if (ch>melodicChans && ins->type==DIV_INS_OPL_DRUMS) {
|
||||
for (int i=0; i<4; i++) {
|
||||
chan[melodicChans+i+1].state.alg=ins->fm.alg;
|
||||
chan[melodicChans+i+1].state.fb=ins->fm.fb;
|
||||
chan[melodicChans+i+1].state.opllPreset=ins->fm.opllPreset;
|
||||
chan[melodicChans+i+1].state.fixedDrums=ins->fm.fixedDrums;
|
||||
chan[melodicChans+i+1].state.kickFreq=ins->fm.kickFreq;
|
||||
chan[melodicChans+i+1].state.snareHatFreq=ins->fm.snareHatFreq;
|
||||
chan[melodicChans+i+1].state.tomTopFreq=ins->fm.tomTopFreq;
|
||||
chan[melodicChans+i+1].state.op[0]=ins->fm.op[i];
|
||||
}
|
||||
} else {
|
||||
chan[ch].state=ins->fm;
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[ch].insChanged) {
|
||||
if (ch>melodicChans && ins->type==DIV_INS_OPL_DRUMS) {
|
||||
for (int i=0; i<4; i++) {
|
||||
int ch=melodicChans+1+i;
|
||||
unsigned char slot=slots[0][ch];
|
||||
if (slot==255) continue;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
DivInstrumentFM::Operator& op=chan[ch].state.op[0];
|
||||
chan[ch].fourOp=false;
|
||||
|
||||
if (isMuted[ch]) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG_BROKEN(63-op.tl,chan[ch].outVol&0x3f,63))|(op.ksl<<6));
|
||||
}
|
||||
|
||||
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
||||
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
|
||||
if (oplType>1) {
|
||||
rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3));
|
||||
}
|
||||
|
||||
if (isMuted[ch]) {
|
||||
oldWrites[chanMap[ch]+ADDR_LR_FB_ALG]=-1;
|
||||
rWrite(chanMap[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&1)|(chan[ch].state.fb<<1));
|
||||
} else {
|
||||
oldWrites[chanMap[ch]+ADDR_LR_FB_ALG]=-1;
|
||||
rWrite(chanMap[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&1)|(chan[ch].state.fb<<1)|((chan[ch].pan&15)<<4));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int ops=(slots[3][ch]!=255 && chan[ch].state.ops==4 && oplType==3)?4:2;
|
||||
chan[ch].fourOp=(ops==4);
|
||||
if (chan[ch].fourOp) {
|
||||
/*
|
||||
if (chan[ch+1].active) {
|
||||
chan[ch+1].keyOff=true;
|
||||
chan[ch+1].keyOn=false;
|
||||
chan[ch+1].active=false;
|
||||
}*/
|
||||
chan[ch+1].insChanged=true;
|
||||
chan[ch+1].macroInit(NULL);
|
||||
}
|
||||
update4OpMask=true;
|
||||
for (int i=0; i<ops; i++) {
|
||||
unsigned char slot=slots[i][ch];
|
||||
if (slot==255) continue;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
DivInstrumentFM::Operator& op=chan[ch].state.op[(ops==4)?orderedOpsL[i]:i];
|
||||
|
||||
if (isMuted[ch]) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
||||
} else {
|
||||
if (KVSL(ch,i) || ch>melodicChans) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG_BROKEN(63-op.tl,chan[ch].outVol&0x3f,63))|(op.ksl<<6));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
|
||||
}
|
||||
}
|
||||
|
||||
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
||||
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
|
||||
if (oplType>1) {
|
||||
rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3));
|
||||
}
|
||||
}
|
||||
|
||||
if (isMuted[ch]) {
|
||||
oldWrites[chanMap[ch]+ADDR_LR_FB_ALG]=-1;
|
||||
rWrite(chanMap[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&1)|(chan[ch].state.fb<<1));
|
||||
if (ops==4) {
|
||||
oldWrites[chanMap[ch+1]+ADDR_LR_FB_ALG]=-1;
|
||||
rWrite(chanMap[ch+1]+ADDR_LR_FB_ALG,((chan[ch].state.alg>>1)&1)|(chan[ch].state.fb<<1));
|
||||
}
|
||||
} else {
|
||||
oldWrites[chanMap[ch]+ADDR_LR_FB_ALG]=-1;
|
||||
rWrite(chanMap[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&1)|(chan[ch].state.fb<<1)|((chan[ch].pan&15)<<4));
|
||||
if (ops==4) {
|
||||
oldWrites[chanMap[ch+1]+ADDR_LR_FB_ALG]=-1;
|
||||
rWrite(chanMap[ch+1]+ADDR_LR_FB_ALG,((chan[ch].state.alg>>1)&1)|(chan[ch].state.fb<<1)|((chan[ch].pan&15)<<4));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformOPL::dispatch(DivCommand c) {
|
||||
if (c.chan>=totalChans && c.chan!=adpcmChan) return 0;
|
||||
// ineffective in 4-op mode
|
||||
|
|
@ -771,114 +914,12 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
}
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,c.chan>melodicChans?DIV_INS_OPL_DRUMS:DIV_INS_OPL);
|
||||
|
||||
if (chan[c.chan].insChanged) {
|
||||
if (c.chan>melodicChans && ins->type==DIV_INS_OPL_DRUMS) {
|
||||
for (int i=0; i<4; i++) {
|
||||
chan[melodicChans+i+1].state.alg=ins->fm.alg;
|
||||
chan[melodicChans+i+1].state.fb=ins->fm.fb;
|
||||
chan[melodicChans+i+1].state.opllPreset=ins->fm.opllPreset;
|
||||
chan[melodicChans+i+1].state.fixedDrums=ins->fm.fixedDrums;
|
||||
chan[melodicChans+i+1].state.kickFreq=ins->fm.kickFreq;
|
||||
chan[melodicChans+i+1].state.snareHatFreq=ins->fm.snareHatFreq;
|
||||
chan[melodicChans+i+1].state.tomTopFreq=ins->fm.tomTopFreq;
|
||||
chan[melodicChans+i+1].state.op[0]=ins->fm.op[i];
|
||||
}
|
||||
} else {
|
||||
chan[c.chan].state=ins->fm;
|
||||
}
|
||||
}
|
||||
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
if (chan[c.chan].insChanged) {
|
||||
if (c.chan>melodicChans && ins->type==DIV_INS_OPL_DRUMS) {
|
||||
for (int i=0; i<4; i++) {
|
||||
int ch=melodicChans+1+i;
|
||||
unsigned char slot=slots[0][ch];
|
||||
if (slot==255) continue;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
DivInstrumentFM::Operator& op=chan[ch].state.op[0];
|
||||
chan[ch].fourOp=false;
|
||||
|
||||
if (isMuted[ch]) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG_BROKEN(63-op.tl,chan[ch].outVol&0x3f,63))|(op.ksl<<6));
|
||||
}
|
||||
|
||||
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
||||
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
|
||||
if (oplType>1) {
|
||||
rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3));
|
||||
}
|
||||
|
||||
if (isMuted[ch]) {
|
||||
oldWrites[chanMap[ch]+ADDR_LR_FB_ALG]=-1;
|
||||
rWrite(chanMap[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&1)|(chan[ch].state.fb<<1));
|
||||
} else {
|
||||
oldWrites[chanMap[ch]+ADDR_LR_FB_ALG]=-1;
|
||||
rWrite(chanMap[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&1)|(chan[ch].state.fb<<1)|((chan[ch].pan&15)<<4));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
chan[c.chan].fourOp=(ops==4);
|
||||
if (chan[c.chan].fourOp) {
|
||||
/*
|
||||
if (chan[c.chan+1].active) {
|
||||
chan[c.chan+1].keyOff=true;
|
||||
chan[c.chan+1].keyOn=false;
|
||||
chan[c.chan+1].active=false;
|
||||
}*/
|
||||
chan[c.chan+1].insChanged=true;
|
||||
chan[c.chan+1].macroInit(NULL);
|
||||
}
|
||||
update4OpMask=true;
|
||||
for (int i=0; i<ops; i++) {
|
||||
unsigned char slot=slots[i][c.chan];
|
||||
if (slot==255) continue;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[i]:i];
|
||||
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
||||
} else {
|
||||
if (KVSL(c.chan,i) || c.chan>melodicChans) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG_BROKEN(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
|
||||
}
|
||||
}
|
||||
|
||||
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
||||
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
|
||||
if (oplType>1) {
|
||||
rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3));
|
||||
}
|
||||
}
|
||||
|
||||
if (isMuted[c.chan]) {
|
||||
oldWrites[chanMap[c.chan]+ADDR_LR_FB_ALG]=-1;
|
||||
rWrite(chanMap[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&1)|(chan[c.chan].state.fb<<1));
|
||||
if (ops==4) {
|
||||
oldWrites[chanMap[c.chan+1]+ADDR_LR_FB_ALG]=-1;
|
||||
rWrite(chanMap[c.chan+1]+ADDR_LR_FB_ALG,((chan[c.chan].state.alg>>1)&1)|(chan[c.chan].state.fb<<1));
|
||||
}
|
||||
} else {
|
||||
oldWrites[chanMap[c.chan]+ADDR_LR_FB_ALG]=-1;
|
||||
rWrite(chanMap[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&1)|(chan[c.chan].state.fb<<1)|((chan[c.chan].pan&15)<<4));
|
||||
if (ops==4) {
|
||||
oldWrites[chanMap[c.chan+1]+ADDR_LR_FB_ALG]=-1;
|
||||
rWrite(chanMap[c.chan+1]+ADDR_LR_FB_ALG,((chan[c.chan].state.alg>>1)&1)|(chan[c.chan].state.fb<<1)|((chan[c.chan].pan&15)<<4));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
commitState(c.chan,ins);
|
||||
chan[c.chan].insChanged=false;
|
||||
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
|
|
@ -1075,6 +1116,11 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
iface.sampleBank=sampleBank;
|
||||
break;
|
||||
case DIV_CMD_LEGATO: {
|
||||
if (chan[c.chan].insChanged) {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
commitState(c.chan,ins);
|
||||
chan[c.chan].insChanged=false;
|
||||
}
|
||||
chan[c.chan].baseFreq=(c.chan==adpcmChan)?(NOTE_ADPCMB(c.value)):(NOTE_FREQUENCY(c.value));
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].freqChanged=true;
|
||||
|
|
@ -1509,7 +1555,11 @@ DivMacroInt* DivPlatformOPL::getChanMacroInt(int ch) {
|
|||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformOPL::getOscBuffer(int ch) {
|
||||
if (ch>=18) return NULL;
|
||||
if (oplType==759) {
|
||||
if (ch>=totalChans+1) return NULL;
|
||||
} else {
|
||||
if (ch>=totalChans) return NULL;
|
||||
}
|
||||
if (oplType==3 && ch<12) {
|
||||
if (chan[ch&(~1)].fourOp) {
|
||||
if (ch&1) {
|
||||
|
|
@ -1640,6 +1690,9 @@ void DivPlatformOPL::notifyInsChange(int ins) {
|
|||
}
|
||||
|
||||
void DivPlatformOPL::notifyInsDeletion(void* ins) {
|
||||
for (int i=0; i<totalChans; i++) {
|
||||
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformOPL::poke(unsigned int addr, unsigned short val) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -100,6 +100,7 @@ class DivPlatformOPL: public DivDispatch {
|
|||
int octave(int freq);
|
||||
int toFreq(int freq);
|
||||
double NOTE_ADPCMB(int note);
|
||||
void commitState(int ch, DivInstrument* ins);
|
||||
|
||||
friend void putDispatchChip(void*,int);
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "opll.h"
|
||||
#include "../engine.h"
|
||||
#include "../../ta-log.h"
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
|
|
@ -331,6 +332,55 @@ void DivPlatformOPLL::muteChannel(int ch, bool mute) {
|
|||
isMuted[ch]=mute;
|
||||
}
|
||||
|
||||
void DivPlatformOPLL::commitState(int ch, DivInstrument* ins) {
|
||||
if (chan[ch].insChanged) {
|
||||
chan[ch].state=ins->fm;
|
||||
}
|
||||
|
||||
if (chan[ch].insChanged) {
|
||||
// update custom preset
|
||||
if (chan[ch].state.opllPreset==0) {
|
||||
DivInstrumentFM::Operator& mod=chan[ch].state.op[0];
|
||||
DivInstrumentFM::Operator& car=chan[ch].state.op[1];
|
||||
rWrite(0x00,(mod.am<<7)|(mod.vib<<6)|((mod.ssgEnv&8)<<2)|(mod.ksr<<4)|(mod.mult));
|
||||
rWrite(0x01,(car.am<<7)|(car.vib<<6)|((car.ssgEnv&8)<<2)|(car.ksr<<4)|(car.mult));
|
||||
rWrite(0x02,(mod.ksl<<6)|(mod.tl&63));
|
||||
rWrite(0x03,(car.ksl<<6)|((chan[ch].state.fms&1)<<4)|((chan[ch].state.ams&1)<<3)|chan[ch].state.fb);
|
||||
rWrite(0x04,(mod.ar<<4)|(mod.dr));
|
||||
rWrite(0x05,(car.ar<<4)|(car.dr));
|
||||
rWrite(0x06,(mod.sl<<4)|(mod.rr));
|
||||
rWrite(0x07,(car.sl<<4)|(car.rr));
|
||||
lastCustomMemory=ch;
|
||||
}
|
||||
if (chan[ch].state.opllPreset==16) { // compatible drums mode
|
||||
if (ch>=6) {
|
||||
drums=true;
|
||||
immWrite(0x16,0x20);
|
||||
immWrite(0x26,0x05);
|
||||
immWrite(0x16,0x20);
|
||||
immWrite(0x26,0x05);
|
||||
immWrite(0x17,0x50);
|
||||
immWrite(0x27,0x05);
|
||||
immWrite(0x17,0x50);
|
||||
immWrite(0x27,0x05);
|
||||
immWrite(0x18,0xC0);
|
||||
immWrite(0x28,0x01);
|
||||
}
|
||||
} else {
|
||||
if (ch>=6) {
|
||||
if (drums) {
|
||||
drums=false;
|
||||
immWrite(0x0e,0);
|
||||
drumState=0;
|
||||
}
|
||||
}
|
||||
if (ch<9) {
|
||||
rWrite(0x30+ch,((15-VOL_SCALE_LOG_BROKEN(chan[ch].outVol,15-chan[ch].state.op[1].tl,15))&15)|(chan[ch].state.opllPreset<<4));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformOPLL::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
|
|
@ -375,49 +425,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
|
||||
if (chan[c.chan].insChanged) {
|
||||
// update custom preset
|
||||
if (chan[c.chan].state.opllPreset==0) {
|
||||
DivInstrumentFM::Operator& mod=chan[c.chan].state.op[0];
|
||||
DivInstrumentFM::Operator& car=chan[c.chan].state.op[1];
|
||||
rWrite(0x00,(mod.am<<7)|(mod.vib<<6)|((mod.ssgEnv&8)<<2)|(mod.ksr<<4)|(mod.mult));
|
||||
rWrite(0x01,(car.am<<7)|(car.vib<<6)|((car.ssgEnv&8)<<2)|(car.ksr<<4)|(car.mult));
|
||||
rWrite(0x02,(mod.ksl<<6)|(mod.tl&63));
|
||||
rWrite(0x03,(car.ksl<<6)|((chan[c.chan].state.fms&1)<<4)|((chan[c.chan].state.ams&1)<<3)|chan[c.chan].state.fb);
|
||||
rWrite(0x04,(mod.ar<<4)|(mod.dr));
|
||||
rWrite(0x05,(car.ar<<4)|(car.dr));
|
||||
rWrite(0x06,(mod.sl<<4)|(mod.rr));
|
||||
rWrite(0x07,(car.sl<<4)|(car.rr));
|
||||
lastCustomMemory=c.chan;
|
||||
}
|
||||
if (chan[c.chan].state.opllPreset==16) { // compatible drums mode
|
||||
if (c.chan>=6) {
|
||||
drums=true;
|
||||
immWrite(0x16,0x20);
|
||||
immWrite(0x26,0x05);
|
||||
immWrite(0x16,0x20);
|
||||
immWrite(0x26,0x05);
|
||||
immWrite(0x17,0x50);
|
||||
immWrite(0x27,0x05);
|
||||
immWrite(0x17,0x50);
|
||||
immWrite(0x27,0x05);
|
||||
immWrite(0x18,0xC0);
|
||||
immWrite(0x28,0x01);
|
||||
}
|
||||
} else {
|
||||
if (c.chan>=6) {
|
||||
if (drums) {
|
||||
drums=false;
|
||||
immWrite(0x0e,0);
|
||||
drumState=0;
|
||||
}
|
||||
}
|
||||
if (c.chan<9) {
|
||||
rWrite(0x30+c.chan,((15-VOL_SCALE_LOG_BROKEN(chan[c.chan].outVol,15-chan[c.chan].state.op[1].tl,15))&15)|(chan[c.chan].state.opllPreset<<4));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
commitState(c.chan,ins);
|
||||
chan[c.chan].insChanged=false;
|
||||
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
|
|
@ -541,6 +549,13 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
|||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
if (c.chan<6 || (!drums && !properDrums)) {
|
||||
if (chan[c.chan].insChanged) {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPLL);
|
||||
commitState(c.chan,ins);
|
||||
chan[c.chan].insChanged=false;
|
||||
}
|
||||
}
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].freqChanged=true;
|
||||
|
|
@ -940,6 +955,9 @@ void DivPlatformOPLL::notifyInsChange(int ins) {
|
|||
}
|
||||
|
||||
void DivPlatformOPLL::notifyInsDeletion(void* ins) {
|
||||
for (int i=0; i<11; i++) {
|
||||
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformOPLL::poke(unsigned int addr, unsigned short val) {
|
||||
|
|
@ -958,6 +976,10 @@ void DivPlatformOPLL::setYMFM(bool use) {
|
|||
useYMFM=use;
|
||||
}
|
||||
|
||||
float DivPlatformOPLL::getPostAmp() {
|
||||
return 1.5f;
|
||||
}
|
||||
|
||||
void DivPlatformOPLL::setFlags(const DivConfig& flags) {
|
||||
int clockSel=flags.getInt("clockSel",0);
|
||||
if (clockSel==3) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -73,6 +73,7 @@ class DivPlatformOPLL: public DivDispatch {
|
|||
|
||||
int octave(int freq);
|
||||
int toFreq(int freq);
|
||||
void commitState(int ch, DivInstrument* ins);
|
||||
|
||||
friend void putDispatchChip(void*,int);
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
|
@ -95,6 +96,7 @@ class DivPlatformOPLL: public DivDispatch {
|
|||
void setYMFM(bool use);
|
||||
bool keyOffAffectsArp(int ch);
|
||||
bool keyOffAffectsPorta(int ch);
|
||||
float getPostAmp();
|
||||
void toggleRegisterDump(bool enable);
|
||||
void setVRC7(bool vrc);
|
||||
void setProperDrums(bool pd);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -163,21 +163,15 @@ void DivPlatformPCE::tick(bool sysTick) {
|
|||
if (chan[i].std.duty.had && i>=4) {
|
||||
chan[i].noise=chan[i].std.duty.val;
|
||||
chan[i].freqChanged=true;
|
||||
int noiseSeek=chan[i].note;
|
||||
if (noiseSeek<0) noiseSeek=0;
|
||||
chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0);
|
||||
}
|
||||
if (NEW_ARP_STRAT) {
|
||||
chan[i].handleArp();
|
||||
int noiseSeek=chan[i].fixedArp?chan[i].baseNoteOverride:(chan[i].note+chan[i].arpOff);
|
||||
if (noiseSeek<0) noiseSeek=0;
|
||||
chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0);
|
||||
} else if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
int noiseSeek=parent->calcArp(chan[i].note,chan[i].std.arp.val);
|
||||
chan[i].baseFreq=NOTE_PERIODIC(noiseSeek);
|
||||
if (noiseSeek<0) noiseSeek=0;
|
||||
chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0);
|
||||
chan[i].noiseSeek=noiseSeek;
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
|
|
@ -246,6 +240,15 @@ void DivPlatformPCE::tick(bool sysTick) {
|
|||
if (chan[i].freq>4095) chan[i].freq=4095;
|
||||
chWrite(i,0x02,chan[i].freq&0xff);
|
||||
chWrite(i,0x03,chan[i].freq>>8);
|
||||
|
||||
if (i>=4) {
|
||||
int noiseSeek=(chan[i].fixedArp?chan[i].baseNoteOverride:(chan[i].note+chan[i].arpOff))+chan[i].pitch2;
|
||||
if (!parent->song.properNoiseLayout && noiseSeek<0) noiseSeek=0;
|
||||
if (!NEW_ARP_STRAT) {
|
||||
noiseSeek=chan[i].noiseSeek;
|
||||
}
|
||||
chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0);
|
||||
}
|
||||
if (chan[i].keyOn) {
|
||||
//rWrite(16+i*5,0x80);
|
||||
//chWrite(i,0x04,0x80|chan[i].vol);
|
||||
|
|
@ -331,9 +334,8 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
|||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
int noiseSeek=chan[c.chan].note;
|
||||
if (noiseSeek<0) noiseSeek=0;
|
||||
chWrite(c.chan,0x07,chan[c.chan].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0);
|
||||
chan[c.chan].noiseSeek=c.value;
|
||||
if (chan[c.chan].noiseSeek<0) chan[c.chan].noiseSeek=0;
|
||||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
|
|
@ -431,7 +433,7 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
|||
}
|
||||
case DIV_CMD_STD_NOISE_MODE:
|
||||
chan[c.chan].noise=c.value;
|
||||
chWrite(c.chan,0x07,chan[c.chan].noise?(0x80|chan[c.chan].note):0);
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_SAMPLE_MODE:
|
||||
chan[c.chan].pcm=c.value;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -34,7 +34,7 @@ class DivPlatformPCE: public DivDispatch {
|
|||
unsigned char pan;
|
||||
bool noise, pcm, furnaceDac, deferredWaveUpdate;
|
||||
signed short wave;
|
||||
int macroVolMul;
|
||||
int macroVolMul, noiseSeek;
|
||||
DivWaveSynth ws;
|
||||
Channel():
|
||||
SharedChannel<signed char>(31),
|
||||
|
|
@ -51,7 +51,8 @@ class DivPlatformPCE: public DivDispatch {
|
|||
furnaceDac(false),
|
||||
deferredWaveUpdate(false),
|
||||
wave(-1),
|
||||
macroVolMul(31) {}
|
||||
macroVolMul(31),
|
||||
noiseSeek(0) {}
|
||||
};
|
||||
Channel chan[6];
|
||||
DivDispatchOscBuffer* oscBuf[6];
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -606,7 +606,7 @@ void DivPlatformQSound::forceIns() {
|
|||
for (int i=0; i<19; i++) {
|
||||
chan[i].insChanged=true;
|
||||
chan[i].freqChanged=true;
|
||||
chan[i].sample=-1;
|
||||
//chan[i].sample=-1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -645,7 +645,7 @@ bool DivPlatformQSound::keyOffAffectsArp(int ch) {
|
|||
}
|
||||
|
||||
void DivPlatformQSound::notifyInsChange(int ins) {
|
||||
for (int i=0; i<4; i++) {
|
||||
for (int i=0; i<19; i++) {
|
||||
if (chan[i].ins==ins) {
|
||||
chan[i].insChanged=true;
|
||||
}
|
||||
|
|
@ -657,7 +657,7 @@ void DivPlatformQSound::notifyWaveChange(int wave) {
|
|||
}
|
||||
|
||||
void DivPlatformQSound::notifyInsDeletion(void* ins) {
|
||||
for (int i=0; i<4; i++) {
|
||||
for (int i=0; i<19; i++) {
|
||||
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||
}
|
||||
}
|
||||
|
|
@ -707,11 +707,11 @@ const void* DivPlatformQSound::getSampleMem(int index) {
|
|||
}
|
||||
|
||||
size_t DivPlatformQSound::getSampleMemCapacity(int index) {
|
||||
return index == 0 ? 16777216 : index == 1 ? MAX(0,16777216 - sampleMemUsage) : 0;
|
||||
return index == 0 ? 16777216 : index == 1 ? (sampleMemUsage>=16777216?1:(16777216 - sampleMemUsage)) : 0;
|
||||
}
|
||||
|
||||
size_t DivPlatformQSound::getSampleMemUsage(int index) {
|
||||
return index == 0 ? sampleMemLen : index == 1 ? MAX(0,sampleMemLenBS - sampleMemUsage) : 0;
|
||||
return index == 0 ? sampleMemLen : index == 1 ? ((sampleMemUsage>=sampleMemLenBS)?0:(sampleMemLenBS - sampleMemUsage)) : 0;
|
||||
}
|
||||
|
||||
bool DivPlatformQSound::isSampleLoaded(int index, int sample) {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue