prepare for Y8950/YMU759 ADPCM
This commit is contained in:
parent
34d868522b
commit
4a563a416e
|
@ -318,8 +318,8 @@ src/engine/platform/sound/vrcvi/vrcvi.cpp
|
||||||
|
|
||||||
src/engine/platform/sound/scc/scc.cpp
|
src/engine/platform/sound/scc/scc.cpp
|
||||||
|
|
||||||
|
src/engine/platform/oplAInterface.cpp
|
||||||
src/engine/platform/ym2608Interface.cpp
|
src/engine/platform/ym2608Interface.cpp
|
||||||
|
|
||||||
src/engine/platform/ym2610Interface.cpp
|
src/engine/platform/ym2610Interface.cpp
|
||||||
|
|
||||||
src/engine/blip_buf.c
|
src/engine/blip_buf.c
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include "opl.h"
|
#include "opl.h"
|
||||||
#include "../engine.h"
|
#include "../engine.h"
|
||||||
|
#include "../../ta-log.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
@ -246,19 +247,48 @@ const char* DivPlatformOPL::getEffectName(unsigned char effect) {
|
||||||
void DivPlatformOPL::acquire_nuked(short* bufL, short* bufR, size_t start, size_t len) {
|
void DivPlatformOPL::acquire_nuked(short* bufL, short* bufR, size_t start, size_t len) {
|
||||||
static short o[2];
|
static short o[2];
|
||||||
static int os[2];
|
static int os[2];
|
||||||
|
static ymfm::ymfm_output<2> aOut;
|
||||||
|
|
||||||
for (size_t h=start; h<start+len; h++) {
|
for (size_t h=start; h<start+len; h++) {
|
||||||
os[0]=0; os[1]=0;
|
os[0]=0; os[1]=0;
|
||||||
if (!writes.empty() && --delay<0) {
|
if (!writes.empty() && --delay<0) {
|
||||||
delay=1;
|
delay=1;
|
||||||
QueuedWrite& w=writes.front();
|
QueuedWrite& w=writes.front();
|
||||||
OPL3_WriteReg(&fm,w.addr,w.val);
|
switch (w.addr) {
|
||||||
|
case 8:
|
||||||
|
if (adpcmChan>=0) {
|
||||||
|
adpcmB->write(w.addr-7,(w.val&15)|0x80);
|
||||||
|
OPL3_WriteReg(&fm,w.addr,w.val&0xc0);
|
||||||
|
} else {
|
||||||
|
OPL3_WriteReg(&fm,w.addr,w.val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 7: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 21: case 22: case 23:
|
||||||
|
if (adpcmChan>=0) {
|
||||||
|
adpcmB->write(w.addr-7,w.val);
|
||||||
|
} else {
|
||||||
|
OPL3_WriteReg(&fm,w.addr,w.val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
OPL3_WriteReg(&fm,w.addr,w.val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
regPool[w.addr&511]=w.val;
|
regPool[w.addr&511]=w.val;
|
||||||
writes.pop();
|
writes.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
OPL3_Generate(&fm,o); os[0]+=o[0]; os[1]+=o[1];
|
OPL3_Generate(&fm,o); os[0]+=o[0]; os[1]+=o[1];
|
||||||
|
|
||||||
|
if (adpcmChan>=0) {
|
||||||
|
adpcmB->clock();
|
||||||
|
aOut.clear();
|
||||||
|
adpcmB->output<2>(aOut,0);
|
||||||
|
|
||||||
|
os[0]+=aOut.data[0];
|
||||||
|
os[1]+=aOut.data[1];
|
||||||
|
}
|
||||||
|
|
||||||
for (int i=0; i<chans; i++) {
|
for (int i=0; i<chans; i++) {
|
||||||
unsigned char ch=outChanMap[i];
|
unsigned char ch=outChanMap[i];
|
||||||
if (ch==255) continue;
|
if (ch==255) continue;
|
||||||
|
@ -1349,8 +1379,9 @@ void DivPlatformOPL::setYMFM(bool use) {
|
||||||
|
|
||||||
void DivPlatformOPL::setOPLType(int type, bool drums) {
|
void DivPlatformOPL::setOPLType(int type, bool drums) {
|
||||||
pretendYMU=false;
|
pretendYMU=false;
|
||||||
|
adpcmChan=-1;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 1: case 2:
|
case 1: case 2: case 8950:
|
||||||
slotsNonDrums=slotsOPL2;
|
slotsNonDrums=slotsOPL2;
|
||||||
slotsDrums=slotsOPL2Drums;
|
slotsDrums=slotsOPL2Drums;
|
||||||
slots=drums?slotsDrums:slotsNonDrums;
|
slots=drums?slotsDrums:slotsNonDrums;
|
||||||
|
@ -1360,6 +1391,9 @@ void DivPlatformOPL::setOPLType(int type, bool drums) {
|
||||||
chans=9;
|
chans=9;
|
||||||
melodicChans=drums?6:9;
|
melodicChans=drums?6:9;
|
||||||
totalChans=drums?11:9;
|
totalChans=drums?11:9;
|
||||||
|
if (type==8950) {
|
||||||
|
adpcmChan=drums?11:9;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 3: case 759:
|
case 3: case 759:
|
||||||
slotsNonDrums=slotsOPL3;
|
slotsNonDrums=slotsOPL3;
|
||||||
|
@ -1371,11 +1405,16 @@ void DivPlatformOPL::setOPLType(int type, bool drums) {
|
||||||
chans=18;
|
chans=18;
|
||||||
melodicChans=drums?15:18;
|
melodicChans=drums?15:18;
|
||||||
totalChans=drums?20:18;
|
totalChans=drums?20:18;
|
||||||
if (type==759) pretendYMU=true;
|
if (type==759) {
|
||||||
|
pretendYMU=true;
|
||||||
|
adpcmChan=16;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (type==759) {
|
if (type==759) {
|
||||||
oplType=3;
|
oplType=3;
|
||||||
|
} else if (type==8950) {
|
||||||
|
oplType=1;
|
||||||
} else {
|
} else {
|
||||||
oplType=type;
|
oplType=type;
|
||||||
}
|
}
|
||||||
|
@ -1425,6 +1464,45 @@ void DivPlatformOPL::setFlags(unsigned int flags) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const void* DivPlatformOPL::getSampleMem(int index) {
|
||||||
|
return (index==0 && adpcmChan>=0) ? adpcmBMem : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t DivPlatformOPL::getSampleMemCapacity(int index) {
|
||||||
|
return (index==0 && adpcmChan>=0) ? 2097152 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t DivPlatformOPL::getSampleMemUsage(int index) {
|
||||||
|
return (index==0 && adpcmChan>=0) ? adpcmBMemLen : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivPlatformOPL::renderSamples() {
|
||||||
|
if (adpcmChan<0) return;
|
||||||
|
memset(adpcmBMem,0,getSampleMemCapacity(0));
|
||||||
|
|
||||||
|
size_t memPos=0;
|
||||||
|
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||||
|
DivSample* s=parent->song.sample[i];
|
||||||
|
int paddedLen=(s->lengthB+255)&(~0xff);
|
||||||
|
if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) {
|
||||||
|
memPos=(memPos+0xfffff)&0xf00000;
|
||||||
|
}
|
||||||
|
if (memPos>=getSampleMemCapacity(0)) {
|
||||||
|
logW("out of ADPCM memory for sample %d!",i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (memPos+paddedLen>=getSampleMemCapacity(0)) {
|
||||||
|
memcpy(adpcmBMem+memPos,s->dataB,getSampleMemCapacity(0)-memPos);
|
||||||
|
logW("out of ADPCM memory for sample %d!",i);
|
||||||
|
} else {
|
||||||
|
memcpy(adpcmBMem+memPos,s->dataB,paddedLen);
|
||||||
|
}
|
||||||
|
s->offB=memPos;
|
||||||
|
memPos+=paddedLen;
|
||||||
|
}
|
||||||
|
adpcmBMemLen=memPos+256;
|
||||||
|
}
|
||||||
|
|
||||||
int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
||||||
parent=p;
|
parent=p;
|
||||||
dumpWrites=false;
|
dumpWrites=false;
|
||||||
|
@ -1437,6 +1515,14 @@ int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, unsigned int f
|
||||||
}
|
}
|
||||||
setFlags(flags);
|
setFlags(flags);
|
||||||
|
|
||||||
|
if (adpcmChan>=0) {
|
||||||
|
adpcmBMem=new unsigned char[getSampleMemCapacity(0)];
|
||||||
|
adpcmBMemLen=0;
|
||||||
|
iface.adpcmBMem=adpcmBMem;
|
||||||
|
iface.sampleBank=0;
|
||||||
|
adpcmB=new ymfm::adpcm_b_engine(iface,2);
|
||||||
|
}
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
return totalChans;
|
return totalChans;
|
||||||
}
|
}
|
||||||
|
@ -1445,6 +1531,10 @@ void DivPlatformOPL::quit() {
|
||||||
for (int i=0; i<18; i++) {
|
for (int i=0; i<18; i++) {
|
||||||
delete oscBuf[i];
|
delete oscBuf[i];
|
||||||
}
|
}
|
||||||
|
if (adpcmChan>=0) {
|
||||||
|
delete adpcmB;
|
||||||
|
delete[] adpcmBMem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DivPlatformOPL::~DivPlatformOPL() {
|
DivPlatformOPL::~DivPlatformOPL() {
|
||||||
|
|
|
@ -23,6 +23,16 @@
|
||||||
#include "../macroInt.h"
|
#include "../macroInt.h"
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include "../../../extern/opl/opl3.h"
|
#include "../../../extern/opl/opl3.h"
|
||||||
|
#include "sound/ymfm/ymfm_adpcm.h"
|
||||||
|
|
||||||
|
class DivOPLAInterface: public ymfm::ymfm_interface {
|
||||||
|
public:
|
||||||
|
unsigned char* adpcmBMem;
|
||||||
|
int sampleBank;
|
||||||
|
uint8_t ymfm_external_read(ymfm::access_class type, uint32_t address);
|
||||||
|
void ymfm_external_write(ymfm::access_class type, uint32_t address, uint8_t data);
|
||||||
|
DivOPLAInterface(): adpcmBMem(NULL), sampleBank(0) {}
|
||||||
|
};
|
||||||
|
|
||||||
class DivPlatformOPL: public DivDispatch {
|
class DivPlatformOPL: public DivDispatch {
|
||||||
protected:
|
protected:
|
||||||
|
@ -73,13 +83,18 @@ class DivPlatformOPL: public DivDispatch {
|
||||||
};
|
};
|
||||||
std::queue<QueuedWrite> writes;
|
std::queue<QueuedWrite> writes;
|
||||||
opl3_chip fm;
|
opl3_chip fm;
|
||||||
|
unsigned char* adpcmBMem;
|
||||||
|
size_t adpcmBMemLen;
|
||||||
|
DivOPLAInterface iface;
|
||||||
|
|
||||||
|
ymfm::adpcm_b_engine* adpcmB;
|
||||||
const unsigned char** slotsNonDrums;
|
const unsigned char** slotsNonDrums;
|
||||||
const unsigned char** slotsDrums;
|
const unsigned char** slotsDrums;
|
||||||
const unsigned char** slots;
|
const unsigned char** slots;
|
||||||
const unsigned short* chanMap;
|
const unsigned short* chanMap;
|
||||||
const unsigned char* outChanMap;
|
const unsigned char* outChanMap;
|
||||||
double chipFreqBase;
|
double chipFreqBase;
|
||||||
int delay, oplType, chans, melodicChans, totalChans;
|
int delay, oplType, chans, melodicChans, totalChans, adpcmChan;
|
||||||
unsigned char lastBusy;
|
unsigned char lastBusy;
|
||||||
unsigned char drumState;
|
unsigned char drumState;
|
||||||
unsigned char drumVol[5];
|
unsigned char drumVol[5];
|
||||||
|
@ -127,6 +142,10 @@ class DivPlatformOPL: public DivDispatch {
|
||||||
void poke(unsigned int addr, unsigned short val);
|
void poke(unsigned int addr, unsigned short val);
|
||||||
void poke(std::vector<DivRegWrite>& wlist);
|
void poke(std::vector<DivRegWrite>& wlist);
|
||||||
const char* getEffectName(unsigned char effect);
|
const char* getEffectName(unsigned char effect);
|
||||||
|
const void* getSampleMem(int index);
|
||||||
|
size_t getSampleMemCapacity(int index);
|
||||||
|
size_t getSampleMemUsage(int index);
|
||||||
|
void renderSamples();
|
||||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||||
void quit();
|
void quit();
|
||||||
~DivPlatformOPL();
|
~DivPlatformOPL();
|
||||||
|
|
38
src/engine/platform/oplAInterface.cpp
Normal file
38
src/engine/platform/oplAInterface.cpp
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sound/ymfm/ymfm.h"
|
||||||
|
#include "opl.h"
|
||||||
|
#include "../engine.h"
|
||||||
|
|
||||||
|
uint8_t DivOPLAInterface::ymfm_external_read(ymfm::access_class type, uint32_t address) {
|
||||||
|
switch (type) {
|
||||||
|
case ymfm::ACCESS_ADPCM_B:
|
||||||
|
if (adpcmBMem==NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return adpcmBMem[address&0xffffff];
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivOPLAInterface::ymfm_external_write(ymfm::access_class type, uint32_t address, uint8_t data) {
|
||||||
|
}
|
Loading…
Reference in a new issue