OPL: ymfm core, part 1
This commit is contained in:
parent
1bcdedda3e
commit
955682b240
9 changed files with 467 additions and 29 deletions
|
|
@ -292,12 +292,252 @@ void DivPlatformOPL::acquire_nuked(short** buf, size_t len) {
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformOPL::acquire_ymfm1(short** buf, size_t len) {
|
||||
ymfm::ymfm_output<1> out;
|
||||
|
||||
ymfm::ym3526::fm_engine* fme=fm_ymfm1->debug_fm_engine();
|
||||
ymfm::fm_channel<ymfm::opl_registers_base<1>>* fmChan[9];
|
||||
|
||||
for (int i=0; i<9; i++) {
|
||||
fmChan[i]=fme->debug_channel(i);
|
||||
}
|
||||
|
||||
for (size_t h=0; h<len; h++) {
|
||||
if (!writes.empty() && --delay<0) {
|
||||
delay=1;
|
||||
QueuedWrite& w=writes.front();
|
||||
|
||||
fm_ymfm1->write(0,w.addr);
|
||||
fm_ymfm1->write(1,w.val);
|
||||
|
||||
regPool[w.addr&511]=w.val;
|
||||
writes.pop();
|
||||
}
|
||||
|
||||
fm_ymfm1->generate(&out,1);
|
||||
|
||||
buf[0][h]=out.data[0];
|
||||
|
||||
if (properDrums) {
|
||||
for (int i=0; i<7; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fmChan[i]->debug_output(0)<<2,-32768,32767);
|
||||
}
|
||||
oscBuf[7]->data[oscBuf[7]->needle++]=CLAMP(fmChan[7]->debug_special1()<<2,-32768,32767);
|
||||
oscBuf[8]->data[oscBuf[8]->needle++]=CLAMP(fmChan[8]->debug_special1()<<2,-32768,32767);
|
||||
oscBuf[9]->data[oscBuf[9]->needle++]=CLAMP(fmChan[8]->debug_special2()<<2,-32768,32767);
|
||||
oscBuf[10]->data[oscBuf[10]->needle++]=CLAMP(fmChan[7]->debug_special2()<<2,-32768,32767);
|
||||
} else {
|
||||
for (int i=0; i<9; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fmChan[i]->debug_output(0)<<2,-32768,32767);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformOPL::acquire_ymfm2(short** buf, size_t len) {
|
||||
ymfm::ymfm_output<1> out;
|
||||
|
||||
ymfm::ym3812::fm_engine* fme=fm_ymfm2->debug_fm_engine();
|
||||
ymfm::fm_channel<ymfm::opl_registers_base<2>>* fmChan[9];
|
||||
|
||||
for (int i=0; i<9; i++) {
|
||||
fmChan[i]=fme->debug_channel(i);
|
||||
}
|
||||
|
||||
for (size_t h=0; h<len; h++) {
|
||||
if (!writes.empty() && --delay<0) {
|
||||
delay=1;
|
||||
QueuedWrite& w=writes.front();
|
||||
|
||||
fm_ymfm2->write(0,w.addr);
|
||||
fm_ymfm2->write(1,w.val);
|
||||
|
||||
regPool[w.addr&511]=w.val;
|
||||
writes.pop();
|
||||
}
|
||||
|
||||
fm_ymfm2->generate(&out,1);
|
||||
|
||||
buf[0][h]=out.data[0];
|
||||
|
||||
if (properDrums) {
|
||||
for (int i=0; i<7; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fmChan[i]->debug_output(0)<<2,-32768,32767);
|
||||
}
|
||||
oscBuf[7]->data[oscBuf[7]->needle++]=CLAMP(fmChan[7]->debug_special1()<<2,-32768,32767);
|
||||
oscBuf[8]->data[oscBuf[8]->needle++]=CLAMP(fmChan[8]->debug_special1()<<2,-32768,32767);
|
||||
oscBuf[9]->data[oscBuf[9]->needle++]=CLAMP(fmChan[8]->debug_special2()<<2,-32768,32767);
|
||||
oscBuf[10]->data[oscBuf[10]->needle++]=CLAMP(fmChan[7]->debug_special2()<<2,-32768,32767);
|
||||
} else {
|
||||
for (int i=0; i<9; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fmChan[i]->debug_output(0)<<2,-32768,32767);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: ADPCM
|
||||
void DivPlatformOPL::acquire_ymfm8950(short** buf, size_t len) {
|
||||
ymfm::ymfm_output<1> out;
|
||||
|
||||
ymfm::y8950::fm_engine* fme=fm_ymfm8950->debug_fm_engine();
|
||||
ymfm::fm_channel<ymfm::opl_registers_base<1>>* fmChan[9];
|
||||
|
||||
for (int i=0; i<9; i++) {
|
||||
fmChan[i]=fme->debug_channel(i);
|
||||
}
|
||||
|
||||
for (size_t h=0; h<len; h++) {
|
||||
if (!writes.empty() && --delay<0) {
|
||||
delay=1;
|
||||
QueuedWrite& w=writes.front();
|
||||
|
||||
fm_ymfm8950->write(0,w.addr);
|
||||
fm_ymfm8950->write(1,w.val);
|
||||
|
||||
regPool[w.addr&511]=w.val;
|
||||
writes.pop();
|
||||
}
|
||||
|
||||
fm_ymfm8950->generate(&out,1);
|
||||
|
||||
buf[0][h]=out.data[0];
|
||||
|
||||
if (properDrums) {
|
||||
for (int i=0; i<7; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fmChan[i]->debug_output(0)<<2,-32768,32767);
|
||||
}
|
||||
oscBuf[7]->data[oscBuf[7]->needle++]=CLAMP(fmChan[7]->debug_special1()<<2,-32768,32767);
|
||||
oscBuf[8]->data[oscBuf[8]->needle++]=CLAMP(fmChan[8]->debug_special1()<<2,-32768,32767);
|
||||
oscBuf[9]->data[oscBuf[9]->needle++]=CLAMP(fmChan[8]->debug_special2()<<2,-32768,32767);
|
||||
oscBuf[10]->data[oscBuf[10]->needle++]=CLAMP(fmChan[7]->debug_special2()<<2,-32768,32767);
|
||||
} else {
|
||||
for (int i=0; i<9; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fmChan[i]->debug_output(0)<<2,-32768,32767);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformOPL::acquire_ymfm3(short** buf, size_t len) {
|
||||
ymfm::ymfm_output<4> out;
|
||||
|
||||
ymfm::ymf262::fm_engine* fme=fm_ymfm3->debug_fm_engine();
|
||||
ymfm::fm_channel<ymfm::opl_registers_base<3>>* fmChan[18];
|
||||
|
||||
for (int i=0; i<18; i++) {
|
||||
fmChan[i]=fme->debug_channel(i);
|
||||
}
|
||||
|
||||
for (size_t h=0; h<len; h++) {
|
||||
if (!writes.empty() && --delay<0) {
|
||||
delay=1;
|
||||
QueuedWrite& w=writes.front();
|
||||
|
||||
fm_ymfm3->write((w.addr&0x100)?2:0,w.addr);
|
||||
fm_ymfm3->write(1,w.val);
|
||||
|
||||
regPool[w.addr&511]=w.val;
|
||||
writes.pop();
|
||||
}
|
||||
|
||||
fm_ymfm3->generate(&out,1);
|
||||
|
||||
buf[0][h]=out.data[0]>>1;
|
||||
if (totalOutputs>1) {
|
||||
buf[1][h]=out.data[1]>>1;
|
||||
}
|
||||
if (totalOutputs>2) {
|
||||
buf[2][h]=out.data[2]>>1;
|
||||
}
|
||||
if (totalOutputs>3) {
|
||||
buf[3][h]=out.data[3]>>1;
|
||||
}
|
||||
if (totalOutputs==6) {
|
||||
// placeholder for OPL4
|
||||
buf[4][h]=0;
|
||||
buf[5][h]=0;
|
||||
}
|
||||
|
||||
// TODO: fix 4-op view
|
||||
if (properDrums) {
|
||||
for (int i=0; i<16; i++) {
|
||||
unsigned char ch=outChanMap[i];
|
||||
if (ch==255) continue;
|
||||
int chOut=fmChan[ch]->debug_output(0);
|
||||
if (chOut==0) {
|
||||
chOut=fmChan[ch]->debug_output(1);
|
||||
}
|
||||
if (chOut==0) {
|
||||
chOut=fmChan[ch]->debug_output(2);
|
||||
}
|
||||
if (chOut==0) {
|
||||
chOut=fmChan[ch]->debug_output(3);
|
||||
}
|
||||
if (i==15) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(chOut,-32768,32767);
|
||||
} else {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(chOut<<1,-32768,32767);
|
||||
}
|
||||
}
|
||||
oscBuf[16]->data[oscBuf[16]->needle++]=CLAMP(fmChan[7]->debug_special2()<<1,-32768,32767);
|
||||
oscBuf[17]->data[oscBuf[17]->needle++]=CLAMP(fmChan[8]->debug_special1()<<1,-32768,32767);
|
||||
oscBuf[18]->data[oscBuf[18]->needle++]=CLAMP(fmChan[8]->debug_special2()<<1,-32768,32767);
|
||||
oscBuf[19]->data[oscBuf[19]->needle++]=CLAMP(fmChan[7]->debug_special1()<<1,-32768,32767);
|
||||
} else {
|
||||
for (int i=0; i<18; i++) {
|
||||
unsigned char ch=outChanMap[i];
|
||||
if (ch==255) continue;
|
||||
int chOut=fmChan[ch]->debug_output(0);
|
||||
if (chOut==0) {
|
||||
chOut=fmChan[ch]->debug_output(1);
|
||||
}
|
||||
if (chOut==0) {
|
||||
chOut=fmChan[ch]->debug_output(2);
|
||||
}
|
||||
if (chOut==0) {
|
||||
chOut=fmChan[ch]->debug_output(3);
|
||||
}
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(chOut<<1,-32768,32767);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformOPL::acquire_nukedLLE2(short** buf, size_t len) {
|
||||
}
|
||||
|
||||
void DivPlatformOPL::acquire_nukedLLE3(short** buf, size_t len) {
|
||||
}
|
||||
|
||||
void DivPlatformOPL::acquire(short** buf, size_t len) {
|
||||
//if (useYMFM) {
|
||||
// acquire_ymfm(buf,len);
|
||||
//} else {
|
||||
if (emuCore==2) { // LLE
|
||||
switch (chipType) {
|
||||
case 1: case 2: case 8950:
|
||||
acquire_nukedLLE2(buf,len);
|
||||
break;
|
||||
case 3: case 759:
|
||||
acquire_nukedLLE3(buf,len);
|
||||
break;
|
||||
}
|
||||
} else if (emuCore==1) { // ymfm
|
||||
switch (chipType) {
|
||||
case 1:
|
||||
acquire_ymfm1(buf,len);
|
||||
break;
|
||||
case 2:
|
||||
acquire_ymfm2(buf,len);
|
||||
break;
|
||||
case 8950:
|
||||
acquire_ymfm8950(buf,len);
|
||||
break;
|
||||
case 3: case 759:
|
||||
acquire_ymfm3(buf,len);
|
||||
break;
|
||||
}
|
||||
} else { // OPL3
|
||||
acquire_nuked(buf,len);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
double DivPlatformOPL::NOTE_ADPCMB(int note) {
|
||||
|
|
@ -1620,17 +1860,34 @@ int DivPlatformOPL::getRegisterPoolSize() {
|
|||
void DivPlatformOPL::reset() {
|
||||
while (!writes.empty()) writes.pop();
|
||||
memset(regPool,0,512);
|
||||
/*
|
||||
if (useYMFM) {
|
||||
fm_ymfm->reset();
|
||||
}
|
||||
*/
|
||||
if (downsample) {
|
||||
const unsigned int downsampledRate=(unsigned int)((double)rate*round(COLOR_NTSC/72.0)/(double)chipRateBase);
|
||||
OPL3_Reset(&fm,downsampledRate);
|
||||
|
||||
const unsigned int downsampledRate=(unsigned int)((double)rate*round(COLOR_NTSC/72.0)/(double)chipRateBase);
|
||||
|
||||
if (emuCore==2) {
|
||||
// TODO: LLE reset
|
||||
} else if (emuCore==1) {
|
||||
switch (chipType) {
|
||||
case 1:
|
||||
fm_ymfm1->reset();
|
||||
break;
|
||||
case 2:
|
||||
fm_ymfm2->reset();
|
||||
break;
|
||||
case 8950:
|
||||
fm_ymfm8950->reset();
|
||||
break;
|
||||
case 3: case 759:
|
||||
fm_ymfm3->reset();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
OPL3_Reset(&fm,rate);
|
||||
if (downsample) {
|
||||
OPL3_Reset(&fm,downsampledRate);
|
||||
} else {
|
||||
OPL3_Reset(&fm,rate);
|
||||
}
|
||||
}
|
||||
|
||||
if (dumpWrites) {
|
||||
addWrite(0xffffffff,0);
|
||||
}
|
||||
|
|
@ -1744,8 +2001,8 @@ int DivPlatformOPL::getPortaFloor(int ch) {
|
|||
return (ch>5)?12:0;
|
||||
}
|
||||
|
||||
void DivPlatformOPL::setYMFM(bool use) {
|
||||
useYMFM=use;
|
||||
void DivPlatformOPL::setCore(unsigned char which) {
|
||||
emuCore=which;
|
||||
}
|
||||
|
||||
void DivPlatformOPL::setOPLType(int type, bool drums) {
|
||||
|
|
@ -1891,11 +2148,13 @@ void DivPlatformOPL::setFlags(const DivConfig& flags) {
|
|||
totalOutputs=4;
|
||||
break;
|
||||
}
|
||||
if (downsample) {
|
||||
const unsigned int downsampledRate=(unsigned int)((double)rate*round(COLOR_NTSC/72.0)/(double)chipRateBase);
|
||||
OPL3_Resample(&fm,downsampledRate);
|
||||
} else {
|
||||
OPL3_Resample(&fm,rate);
|
||||
if (emuCore!=1 && emuCore!=2) {
|
||||
if (downsample) {
|
||||
const unsigned int downsampledRate=(unsigned int)((double)rate*round(COLOR_NTSC/72.0)/(double)chipRateBase);
|
||||
OPL3_Resample(&fm,downsampledRate);
|
||||
} else {
|
||||
OPL3_Resample(&fm,rate);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
|
|
@ -1990,6 +2249,29 @@ int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, const DivConfi
|
|||
for (int i=0; i<20; i++) {
|
||||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
}
|
||||
|
||||
fm_ymfm1=NULL;
|
||||
fm_ymfm2=NULL;
|
||||
fm_ymfm8950=NULL;
|
||||
fm_ymfm3=NULL;
|
||||
|
||||
if (emuCore==1) {
|
||||
switch (chipType) {
|
||||
case 1:
|
||||
fm_ymfm1=new ymfm::ym3526(iface);
|
||||
break;
|
||||
case 2:
|
||||
fm_ymfm2=new ymfm::ym3812(iface);
|
||||
break;
|
||||
case 8950:
|
||||
fm_ymfm8950=new ymfm::y8950(iface);
|
||||
break;
|
||||
case 3: case 759:
|
||||
fm_ymfm3=new ymfm::ymf262(iface);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
setFlags(flags);
|
||||
|
||||
if (adpcmChan>=0) {
|
||||
|
|
@ -2012,6 +2294,22 @@ void DivPlatformOPL::quit() {
|
|||
delete adpcmB;
|
||||
delete[] adpcmBMem;
|
||||
}
|
||||
if (fm_ymfm1!=NULL) {
|
||||
delete fm_ymfm1;
|
||||
fm_ymfm1=NULL;
|
||||
}
|
||||
if (fm_ymfm2!=NULL) {
|
||||
delete fm_ymfm2;
|
||||
fm_ymfm2=NULL;
|
||||
}
|
||||
if (fm_ymfm8950!=NULL) {
|
||||
delete fm_ymfm8950;
|
||||
fm_ymfm8950=NULL;
|
||||
}
|
||||
if (fm_ymfm3!=NULL) {
|
||||
delete fm_ymfm3;
|
||||
fm_ymfm3=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
DivPlatformOPL::~DivPlatformOPL() {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,12 @@
|
|||
#include "../dispatch.h"
|
||||
#include "../../fixedQueue.h"
|
||||
#include "../../../extern/opl/opl3.h"
|
||||
extern "C" {
|
||||
#include "../../../extern/YM3812-LLE/fmopl2.h"
|
||||
#include "../../../extern/YMF262-LLE/fmopl3.h"
|
||||
}
|
||||
#include "sound/ymfm/ymfm_adpcm.h"
|
||||
#include "sound/ymfm/ymfm_opl.h"
|
||||
|
||||
class DivOPLAInterface: public ymfm::ymfm_interface {
|
||||
public:
|
||||
|
|
@ -68,7 +73,7 @@ class DivPlatformOPL: public DivDispatch {
|
|||
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {}
|
||||
};
|
||||
FixedQueue<QueuedWrite,2048> writes;
|
||||
opl3_chip fm;
|
||||
|
||||
unsigned char* adpcmBMem;
|
||||
size_t adpcmBMemLen;
|
||||
DivOPLAInterface iface;
|
||||
|
|
@ -93,11 +98,25 @@ class DivPlatformOPL: public DivDispatch {
|
|||
|
||||
unsigned char lfoValue;
|
||||
|
||||
bool useYMFM, update4OpMask, pretendYMU, downsample, compatPan;
|
||||
// 0: Nuked-OPL3
|
||||
// 1: ymfm
|
||||
// 2: YM3812-LLE/YMF262-LLE
|
||||
unsigned char emuCore;
|
||||
|
||||
bool update4OpMask, pretendYMU, downsample, compatPan;
|
||||
|
||||
short oldWrites[512];
|
||||
short pendingWrites[512];
|
||||
|
||||
// chips
|
||||
opl3_chip fm;
|
||||
ymfm::ym3526* fm_ymfm1;
|
||||
ymfm::ym3812* fm_ymfm2;
|
||||
ymfm::y8950* fm_ymfm8950;
|
||||
ymfm::ymf262* fm_ymfm3;
|
||||
fmopl2_t fm_lle2;
|
||||
fmopl3_t fm_lle3;
|
||||
|
||||
int octave(int freq);
|
||||
int toFreq(int freq);
|
||||
double NOTE_ADPCMB(int note);
|
||||
|
|
@ -106,8 +125,13 @@ class DivPlatformOPL: public DivDispatch {
|
|||
friend void putDispatchChip(void*,int);
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
||||
void acquire_nukedLLE2(short** buf, size_t len);
|
||||
void acquire_nukedLLE3(short** buf, size_t len);
|
||||
void acquire_nuked(short** buf, size_t len);
|
||||
//void acquire_ymfm(short** buf, size_t len);
|
||||
void acquire_ymfm3(short** buf, size_t len);
|
||||
void acquire_ymfm8950(short** buf, size_t len);
|
||||
void acquire_ymfm2(short** buf, size_t len);
|
||||
void acquire_ymfm1(short** buf, size_t len);
|
||||
|
||||
public:
|
||||
void acquire(short** buf, size_t len);
|
||||
|
|
@ -124,7 +148,7 @@ class DivPlatformOPL: public DivDispatch {
|
|||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
int getOutputCount();
|
||||
void setYMFM(bool use);
|
||||
void setCore(unsigned char which);
|
||||
void setOPLType(int type, bool drums);
|
||||
bool keyOffAffectsArp(int ch);
|
||||
bool keyOffAffectsPorta(int ch);
|
||||
|
|
|
|||
|
|
@ -305,6 +305,8 @@ public:
|
|||
// simple getters for debugging
|
||||
fm_operator<RegisterType> *debug_operator(uint32_t index) const { return m_op[index]; }
|
||||
int32_t debug_output(uint32_t index) const { return m_output[index]; }
|
||||
int32_t debug_special1() const { return m_special1; }
|
||||
int32_t debug_special2() const { return m_special2; }
|
||||
|
||||
private:
|
||||
// helper to add values to the outputs based on channel enables
|
||||
|
|
@ -343,6 +345,8 @@ private:
|
|||
RegisterType &m_regs; // direct reference to registers
|
||||
fm_engine_base<RegisterType> &m_owner; // reference to the owning engine
|
||||
mutable int32_t m_output[4];
|
||||
mutable int32_t m_special1;
|
||||
mutable int32_t m_special2;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -808,7 +808,9 @@ fm_channel<RegisterType>::fm_channel(fm_engine_base<RegisterType> &owner, uint32
|
|||
m_op{ nullptr, nullptr, nullptr, nullptr },
|
||||
m_regs(owner.regs()),
|
||||
m_owner(owner),
|
||||
m_output{ 0, 0, 0, 0 }
|
||||
m_output{ 0, 0, 0, 0 },
|
||||
m_special1(0),
|
||||
m_special2(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -1139,13 +1141,13 @@ void fm_channel<RegisterType>::output_rhythm_ch7(uint32_t phase_select, output_d
|
|||
// and a combination of noise and the operator 13/17 phase select
|
||||
// to compute the phase
|
||||
uint32_t phase = (phase_select << 9) | (0xd0 >> (2 * (noise_state ^ phase_select)));
|
||||
int32_t result = m_op[0]->compute_volume(phase, am_offset) >> rshift;
|
||||
int32_t result = m_special1 = m_op[0]->compute_volume(phase, am_offset) >> rshift;
|
||||
|
||||
// Snare Drum: this uses the envelope from operator 16 (channel 7),
|
||||
// and a combination of noise and operator 13 phase to pick a phase
|
||||
uint32_t op13phase = m_op[0]->phase();
|
||||
phase = (0x100 << bitfield(op13phase, 8)) ^ (noise_state << 8);
|
||||
result += m_op[1]->compute_volume(phase, am_offset) >> rshift;
|
||||
result += m_special2 = m_op[1]->compute_volume(phase, am_offset) >> rshift;
|
||||
result = clamp(result, -clipmax - 1, clipmax);
|
||||
|
||||
// add to the output
|
||||
|
|
@ -1166,12 +1168,12 @@ void fm_channel<RegisterType>::output_rhythm_ch8(uint32_t phase_select, output_d
|
|||
uint32_t am_offset = m_regs.lfo_am_offset(m_choffs);
|
||||
|
||||
// Tom Tom: this is just a single operator processed normally
|
||||
int32_t result = m_op[0]->compute_volume(m_op[0]->phase(), am_offset) >> rshift;
|
||||
int32_t result = m_special1 = m_op[0]->compute_volume(m_op[0]->phase(), am_offset) >> rshift;
|
||||
|
||||
// Top Cymbal: this uses the envelope from operator 17 (channel 8),
|
||||
// and the operator 13/17 phase select to compute the phase
|
||||
uint32_t phase = 0x100 | (phase_select << 9);
|
||||
result += m_op[1]->compute_volume(phase, am_offset) >> rshift;
|
||||
result += m_special2 = m_op[1]->compute_volume(phase, am_offset) >> rshift;
|
||||
result = clamp(result, -clipmax - 1, clipmax);
|
||||
|
||||
// add to the output
|
||||
|
|
|
|||
|
|
@ -528,6 +528,8 @@ public:
|
|||
|
||||
// generate samples of sound
|
||||
void generate(output_data *output, uint32_t numsamples = 1);
|
||||
|
||||
fm_engine* debug_fm_engine() { return &m_fm; }
|
||||
protected:
|
||||
// internal state
|
||||
uint8_t m_address; // address register
|
||||
|
|
@ -575,6 +577,9 @@ public:
|
|||
// generate samples of sound
|
||||
void generate(output_data *output, uint32_t numsamples = 1);
|
||||
|
||||
fm_engine* debug_fm_engine() { return &m_fm; }
|
||||
adpcm_b_engine* debug_adpcm_b_engine() { return &m_adpcm_b; }
|
||||
|
||||
protected:
|
||||
// internal state
|
||||
uint8_t m_address; // address register
|
||||
|
|
@ -623,6 +628,8 @@ public:
|
|||
// generate samples of sound
|
||||
void generate(output_data *output, uint32_t numsamples = 1);
|
||||
|
||||
fm_engine* debug_fm_engine() { return &m_fm; }
|
||||
|
||||
protected:
|
||||
// internal state
|
||||
uint8_t m_address; // address register
|
||||
|
|
@ -670,6 +677,8 @@ public:
|
|||
// generate samples of sound
|
||||
void generate(output_data *output, uint32_t numsamples = 1);
|
||||
|
||||
fm_engine* debug_fm_engine() { return &m_fm; }
|
||||
|
||||
protected:
|
||||
// internal state
|
||||
uint16_t m_address; // address register
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue