mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-26 06:25:16 +00:00
prepare for Y8950/YMU759 ADPCM
This commit is contained in:
parent
34d868522b
commit
4a563a416e
4 changed files with 152 additions and 5 deletions
|
@ -318,8 +318,8 @@ src/engine/platform/sound/vrcvi/vrcvi.cpp
|
|||
|
||||
src/engine/platform/sound/scc/scc.cpp
|
||||
|
||||
src/engine/platform/oplAInterface.cpp
|
||||
src/engine/platform/ym2608Interface.cpp
|
||||
|
||||
src/engine/platform/ym2610Interface.cpp
|
||||
|
||||
src/engine/blip_buf.c
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "opl.h"
|
||||
#include "../engine.h"
|
||||
#include "../../ta-log.h"
|
||||
#include <string.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) {
|
||||
static short o[2];
|
||||
static int os[2];
|
||||
static ymfm::ymfm_output<2> aOut;
|
||||
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
os[0]=0; os[1]=0;
|
||||
if (!writes.empty() && --delay<0) {
|
||||
delay=1;
|
||||
QueuedWrite& w=writes.front();
|
||||
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;
|
||||
writes.pop();
|
||||
}
|
||||
|
||||
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++) {
|
||||
unsigned char ch=outChanMap[i];
|
||||
if (ch==255) continue;
|
||||
|
@ -1349,8 +1379,9 @@ void DivPlatformOPL::setYMFM(bool use) {
|
|||
|
||||
void DivPlatformOPL::setOPLType(int type, bool drums) {
|
||||
pretendYMU=false;
|
||||
adpcmChan=-1;
|
||||
switch (type) {
|
||||
case 1: case 2:
|
||||
case 1: case 2: case 8950:
|
||||
slotsNonDrums=slotsOPL2;
|
||||
slotsDrums=slotsOPL2Drums;
|
||||
slots=drums?slotsDrums:slotsNonDrums;
|
||||
|
@ -1360,6 +1391,9 @@ void DivPlatformOPL::setOPLType(int type, bool drums) {
|
|||
chans=9;
|
||||
melodicChans=drums?6:9;
|
||||
totalChans=drums?11:9;
|
||||
if (type==8950) {
|
||||
adpcmChan=drums?11:9;
|
||||
}
|
||||
break;
|
||||
case 3: case 759:
|
||||
slotsNonDrums=slotsOPL3;
|
||||
|
@ -1371,11 +1405,16 @@ void DivPlatformOPL::setOPLType(int type, bool drums) {
|
|||
chans=18;
|
||||
melodicChans=drums?15:18;
|
||||
totalChans=drums?20:18;
|
||||
if (type==759) pretendYMU=true;
|
||||
if (type==759) {
|
||||
pretendYMU=true;
|
||||
adpcmChan=16;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (type==759) {
|
||||
oplType=3;
|
||||
} else if (type==8950) {
|
||||
oplType=1;
|
||||
} else {
|
||||
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) {
|
||||
parent=p;
|
||||
dumpWrites=false;
|
||||
|
@ -1437,6 +1515,14 @@ int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, unsigned int f
|
|||
}
|
||||
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();
|
||||
return totalChans;
|
||||
}
|
||||
|
@ -1445,6 +1531,10 @@ void DivPlatformOPL::quit() {
|
|||
for (int i=0; i<18; i++) {
|
||||
delete oscBuf[i];
|
||||
}
|
||||
if (adpcmChan>=0) {
|
||||
delete adpcmB;
|
||||
delete[] adpcmBMem;
|
||||
}
|
||||
}
|
||||
|
||||
DivPlatformOPL::~DivPlatformOPL() {
|
||||
|
|
|
@ -23,6 +23,16 @@
|
|||
#include "../macroInt.h"
|
||||
#include <queue>
|
||||
#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 {
|
||||
protected:
|
||||
|
@ -73,13 +83,18 @@ class DivPlatformOPL: public DivDispatch {
|
|||
};
|
||||
std::queue<QueuedWrite> writes;
|
||||
opl3_chip fm;
|
||||
unsigned char* adpcmBMem;
|
||||
size_t adpcmBMemLen;
|
||||
DivOPLAInterface iface;
|
||||
|
||||
ymfm::adpcm_b_engine* adpcmB;
|
||||
const unsigned char** slotsNonDrums;
|
||||
const unsigned char** slotsDrums;
|
||||
const unsigned char** slots;
|
||||
const unsigned short* chanMap;
|
||||
const unsigned char* outChanMap;
|
||||
double chipFreqBase;
|
||||
int delay, oplType, chans, melodicChans, totalChans;
|
||||
int delay, oplType, chans, melodicChans, totalChans, adpcmChan;
|
||||
unsigned char lastBusy;
|
||||
unsigned char drumState;
|
||||
unsigned char drumVol[5];
|
||||
|
@ -127,6 +142,10 @@ class DivPlatformOPL: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
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);
|
||||
void quit();
|
||||
~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