
* 'master' of https://github.com/tildearrow/furnace: (70 commits) whoops GUI: AY8930 credits GUI: fix inability to close subsongs BANK OPN: wire up ExtCh system fix build failure dev95 - multiple songs in a single file (READ) DO NOT USE - THIS FAILS - WORK IN PROGRESS enforce asset limits old .dmf loading improvements add AICA and YMZ ADPCM formats allocate ID for YMZ280B harden .fur file saver Fix AY VGM output, Fix presets preparations for UI improvements GUI: add more presets prepare for ExtCh OPN/OPNA GUI: clarify that lock layout doesn't work yet GUI: remember last state of order edit mode GUI: store edit/followOrders/followPattern state ... # Conflicts: # src/engine/fileOps.cpp # src/engine/platform/ym2610.cpp # src/engine/platform/ym2610b.cpp # src/engine/sample.cpp # src/engine/sample.h # src/engine/sysDef.cpp # src/gui/doAction.cpp # src/gui/sysConf.cpp
279 lines
8.4 KiB
C++
279 lines
8.4 KiB
C++
/**
|
|
* Furnace Tracker - multi-system chiptune tracker
|
|
* Copyright (C) 2021-2022 tildearrow and contributors
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#ifndef _ES5506_H
|
|
#define _ES5506_H
|
|
|
|
#pragma once
|
|
|
|
#include "../dispatch.h"
|
|
#include "../engine.h"
|
|
#include <queue>
|
|
#include "../macroInt.h"
|
|
#include "../sample.h"
|
|
#include "sound/es550x/es5506.hpp"
|
|
|
|
class DivPlatformES5506: public DivDispatch, public es550x_intf {
|
|
struct Channel {
|
|
struct PCM {
|
|
int index, next;
|
|
int note;
|
|
double freqOffs;
|
|
double nextFreqOffs;
|
|
bool reversed, pause;
|
|
unsigned int bank;
|
|
unsigned int start;
|
|
unsigned int end;
|
|
unsigned int length;
|
|
unsigned int loopStart;
|
|
unsigned int loopEnd;
|
|
DivSampleLoopMode loopMode;
|
|
PCM():
|
|
index(-1),
|
|
next(-1),
|
|
note(0),
|
|
freqOffs(1.0),
|
|
nextFreqOffs(1.0),
|
|
reversed(false),
|
|
pause(false),
|
|
bank(0),
|
|
start(0),
|
|
end(0),
|
|
length(0),
|
|
loopStart(0),
|
|
loopEnd(0),
|
|
loopMode(DIV_SAMPLE_LOOPMODE_ONESHOT) {}
|
|
} pcm;
|
|
int freq, baseFreq, nextFreq, pitch, pitch2, note, nextNote, prevNote, ins, wave;
|
|
unsigned int volMacroMax, panMacroMax;
|
|
bool active, insChanged, freqChanged, pcmChanged, keyOn, keyOff, inPorta, useWave, isReverseLoop;
|
|
|
|
struct NoteChanged { // Note changed flags
|
|
union { // pack flag bits in single byte
|
|
struct { // flag bits
|
|
unsigned char offs: 1; // frequency offset
|
|
unsigned char note: 1; // note
|
|
unsigned char freq: 1; // base frequency
|
|
unsigned char dummy: 5; // dummy for bit padding
|
|
};
|
|
unsigned char changed; // Packed flags are stored here
|
|
};
|
|
|
|
NoteChanged() :
|
|
changed(0) {}
|
|
} noteChanged;
|
|
|
|
struct VolChanged { // Volume changed flags
|
|
union { // pack flag bits in single byte
|
|
struct { // flag bits
|
|
unsigned char lVol: 1; // left volume
|
|
unsigned char rVol: 1; // right volume
|
|
unsigned char dummy: 6; // dummy for bit padding
|
|
};
|
|
unsigned char changed; // Packed flags are stored here
|
|
};
|
|
|
|
VolChanged() :
|
|
changed(0) {}
|
|
} volChanged;
|
|
|
|
struct FilterChanged { // Filter changed flags
|
|
union { // pack flag bits in single byte
|
|
struct { // flag bits
|
|
unsigned char mode: 1; // Filter mode
|
|
unsigned char k1: 1; // K1
|
|
unsigned char k2: 1; // K2
|
|
unsigned char dummy: 5; // dummy for bit padding
|
|
};
|
|
unsigned char changed; // Packed flags are stored here
|
|
};
|
|
|
|
FilterChanged():
|
|
changed(0) {}
|
|
} filterChanged;
|
|
|
|
struct EnvChanged { // Envelope changed flags
|
|
union { // pack flag bits in single byte
|
|
struct { // flag bits
|
|
unsigned char ecount: 1; // Envelope count
|
|
unsigned char lVRamp: 1; // Left volume Ramp
|
|
unsigned char rVRamp: 1; // Right volume Ramp
|
|
unsigned char k1Ramp: 1; // K1 Ramp w/Slow flag
|
|
unsigned char k2Ramp: 1; // K2 Ramp w/Slow flag
|
|
unsigned char dummy: 3; // dummy for bit padding
|
|
};
|
|
unsigned char changed; // Packed flags are stored here
|
|
};
|
|
|
|
EnvChanged():
|
|
changed(0) {}
|
|
} envChanged;
|
|
|
|
signed int k1Offs, k2Offs;
|
|
signed int k1Slide, k2Slide;
|
|
signed int k1Prev, k2Prev;
|
|
unsigned int vol, lVol, rVol;
|
|
unsigned int outVol, outLVol, outRVol;
|
|
unsigned int resLVol, resRVol;
|
|
signed int lOut, rOut, oscOut;
|
|
DivInstrumentES5506::Filter filter;
|
|
DivInstrumentES5506::Envelope envelope;
|
|
DivInstrumentAmiga::TransWave transWave;
|
|
DivMacroInt std;
|
|
void macroInit(DivInstrument* which) {
|
|
std.init(which);
|
|
pitch2=0;
|
|
if (std.ex1.mode==2) {
|
|
k1Offs=0;
|
|
}
|
|
if (std.ex1.mode==2) {
|
|
k2Offs=0;
|
|
}
|
|
k1Prev=0xffff;
|
|
k2Prev=0xffff;
|
|
}
|
|
Channel():
|
|
freq(0),
|
|
baseFreq(0),
|
|
nextFreq(0),
|
|
pitch(0),
|
|
pitch2(0),
|
|
note(0),
|
|
nextNote(0),
|
|
prevNote(0),
|
|
ins(-1),
|
|
wave(-1),
|
|
volMacroMax(0xffff),
|
|
panMacroMax(0xffff),
|
|
active(false),
|
|
insChanged(true),
|
|
freqChanged(false),
|
|
pcmChanged(false),
|
|
keyOn(false),
|
|
keyOff(false),
|
|
inPorta(false),
|
|
useWave(false),
|
|
isReverseLoop(false),
|
|
k1Offs(0),
|
|
k2Offs(0),
|
|
k1Slide(0),
|
|
k2Slide(0),
|
|
k1Prev(0xffff),
|
|
k2Prev(0xffff),
|
|
vol(0xff),
|
|
lVol(0xff),
|
|
rVol(0xff),
|
|
outVol(0xffff),
|
|
outLVol(0xffff),
|
|
outRVol(0xffff),
|
|
resLVol(0xffff),
|
|
resRVol(0xffff),
|
|
lOut(0),
|
|
rOut(0),
|
|
oscOut(0) {}
|
|
};
|
|
Channel chan[32];
|
|
DivDispatchOscBuffer* oscBuf[32];
|
|
bool isMuted[32];
|
|
signed short* sampleMem; // ES5506 uses 16 bit data bus for samples
|
|
size_t sampleMemLen;
|
|
struct QueuedHostIntf {
|
|
unsigned char step;
|
|
unsigned char addr;
|
|
unsigned int val;
|
|
unsigned int mask;
|
|
unsigned int* read;
|
|
unsigned short delay;
|
|
bool isRead;
|
|
QueuedHostIntf(unsigned char s, unsigned char a, unsigned int v, unsigned int m=(unsigned int)(~0), unsigned short d=0):
|
|
step(s),
|
|
addr(a),
|
|
val(v),
|
|
mask(m),
|
|
read(NULL),
|
|
delay(0),
|
|
isRead(false) {}
|
|
QueuedHostIntf(unsigned char s, unsigned char a, unsigned int* r, unsigned int m=(unsigned int)(~0), unsigned short d=0):
|
|
step(s),
|
|
addr(a),
|
|
val(0),
|
|
mask(m),
|
|
read(r),
|
|
delay(d),
|
|
isRead(true) {}
|
|
};
|
|
std::queue<QueuedHostIntf> hostIntf32;
|
|
std::queue<QueuedHostIntf> hostIntf8;
|
|
int cycle, curPage;
|
|
unsigned char maskedVal;
|
|
unsigned int irqv;
|
|
bool isMasked, isReaded;
|
|
bool irqTrigger;
|
|
unsigned char prevChanCycle;
|
|
|
|
unsigned char initChanMax, chanMax;
|
|
|
|
es5506_core es5506;
|
|
unsigned char regPool[4*16*128]; // 7 bit page x 16 registers per page x 32 bit per registers
|
|
|
|
friend void putDispatchChan(void*,int,int);
|
|
|
|
public:
|
|
virtual void e_pin(bool state) override; // E output
|
|
|
|
virtual void irqb(bool state) override; // IRQB output
|
|
virtual s16 read_sample(u8 voice, u8 bank, u32 address) override {
|
|
if (sampleMem==NULL) return 0;
|
|
return sampleMem[((bank&3)<<21)|(address&0x1fffff)];
|
|
}
|
|
|
|
virtual void acquire(short* bufL, short* bufR, size_t start, size_t len) override;
|
|
virtual int dispatch(DivCommand c) override;
|
|
virtual void* getChanState(int chan) override;
|
|
virtual DivDispatchOscBuffer* getOscBuffer(int chan) override;
|
|
virtual unsigned char* getRegisterPool() override;
|
|
virtual int getRegisterPoolSize() override;
|
|
virtual void reset() override;
|
|
virtual void forceIns() override;
|
|
virtual void tick(bool sysTick=true) override;
|
|
virtual void muteChannel(int ch, bool mute) override;
|
|
virtual bool isStereo() override;
|
|
virtual bool keyOffAffectsArp(int ch) override;
|
|
virtual void setFlags(unsigned int flags) override;
|
|
virtual void notifyInsChange(int ins) override;
|
|
virtual void notifyWaveChange(int wave) override;
|
|
virtual void notifyInsDeletion(void* ins) override;
|
|
virtual void poke(unsigned int addr, unsigned short val) override;
|
|
virtual void poke(std::vector<DivRegWrite>& wlist) override;
|
|
virtual const void* getSampleMem(int index = 0) override;
|
|
virtual size_t getSampleMemCapacity(int index = 0) override;
|
|
virtual size_t getSampleMemUsage(int index = 0) override;
|
|
virtual void renderSamples() override;
|
|
virtual const char** getRegisterSheet() override;
|
|
virtual const char* getEffectName(unsigned char effect) override;
|
|
virtual int init(DivEngine* parent, int channels, int sugRate, unsigned int flags) override;
|
|
virtual void quit() override;
|
|
DivPlatformES5506():
|
|
DivDispatch(),
|
|
es550x_intf(),
|
|
es5506(*this) {}
|
|
};
|
|
|
|
#endif
|