SegaPCM: new real emulation core

This commit is contained in:
tildearrow 2023-02-10 02:01:23 -05:00
parent 0d424c7962
commit 6036366f38
9 changed files with 144 additions and 169 deletions

View File

@ -23,47 +23,25 @@
#include <string.h>
#include <math.h>
//#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;}
//#define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} }
#define rWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} }
#define chWrite(c,a,v) rWrite(((c)<<3)+(a),v)
void DivPlatformSegaPCM::acquire(short** buf, size_t len) {
static int os[2];
for (size_t h=0; h<len; h++) {
os[0]=0; os[1]=0;
// do a PCM cycle
pcmL=0; pcmR=0;
for (int i=0; i<16; i++) {
if (chan[i].pcm.sample>=0 && chan[i].pcm.sample<parent->song.sampleLen) {
DivSample* s=parent->getSample(chan[i].pcm.sample);
if (s->samples<=0) {
chan[i].pcm.sample=-1;
oscBuf[i]->data[oscBuf[i]->needle++]=0;
continue;
}
if (!isMuted[i]) {
oscBuf[i]->data[oscBuf[i]->needle++]=s->data8[chan[i].pcm.pos>>8]*(chan[i].chVolL+chan[i].chVolR)>>1;
pcmL+=(s->data8[chan[i].pcm.pos>>8]*chan[i].chVolL);
pcmR+=(s->data8[chan[i].pcm.pos>>8]*chan[i].chVolR);
} else {
oscBuf[i]->data[oscBuf[i]->needle++]=0;
}
chan[i].pcm.pos+=chan[i].pcm.freq;
if (s->isLoopable() && chan[i].pcm.pos>=((unsigned int)s->loopEnd<<8)) {
chan[i].pcm.pos=s->loopStart<<8;
} else if (chan[i].pcm.pos>=(s->samples<<8)) {
chan[i].pcm.sample=-1;
}
} else {
oscBuf[i]->data[oscBuf[i]->needle++]=0;
}
while (!writes.empty()) {
QueuedWrite w=writes.front();
pcm.write(w.addr,w.val);
regPool[w.addr&0xff]=w.val;
writes.pop();
}
os[0]=pcmL;
pcm.sound_stream_update(os);
if (os[0]<-32768) os[0]=-32768;
if (os[0]>32767) os[0]=32767;
os[1]=pcmR;
if (os[1]<-32768) os[1]=-32768;
if (os[1]>32767) os[1]=32767;
@ -81,10 +59,8 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
chan[i].outVol=(chan[i].vol*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul;
chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127;
chan[i].chVolR=(chan[i].outVol*chan[i].chPanR)/127;
if (dumpWrites) {
addWrite(0x10002+(i<<3),chan[i].chVolL);
addWrite(0x10003+(i<<3),chan[i].chVolR);
}
rWrite(2+(i<<3),chan[i].chVolL);
rWrite(3+(i<<3),chan[i].chVolR);
}
}
@ -100,17 +76,13 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
if (parent->song.newSegaPCM) if (chan[i].std.panL.had) {
chan[i].chPanL=chan[i].std.panL.val&127;
chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127;
if (dumpWrites) {
addWrite(0x10002+(i<<3),chan[i].chVolL);
}
rWrite(2+(i<<3),chan[i].chVolL);
}
if (parent->song.newSegaPCM) if (chan[i].std.panR.had) {
chan[i].chPanR=chan[i].std.panR.val&127;
chan[i].chVolR=(chan[i].outVol*chan[i].chPanR)/127;
if (dumpWrites) {
addWrite(0x10003+(i<<3),chan[i].chVolR);
}
rWrite(3+(i<<3),chan[i].chVolR);
}
if (chan[i].std.pitch.had) {
@ -145,56 +117,48 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
off=(double)s->centerRate/8363.0;
}
chan[i].pcm.freq=MIN(255,(15625+(off*parent->song.tuning*pow(2.0,double(chan[i].freq+256)/(64.0*12.0)))*255)/31250)+chan[i].pitch2;
if (dumpWrites) {
addWrite(0x10007+(i<<3),chan[i].pcm.freq);
}
rWrite(7+(i<<3),chan[i].pcm.freq);
}
chan[i].freqChanged=false;
if (chan[i].keyOn || chan[i].keyOff) {
if (chan[i].keyOn && !chan[i].keyOff) {
if (dumpWrites) {
addWrite(0x10086+(i<<3),3);
}
rWrite(0x86+(i<<3),3);
chan[i].pcm.pos=0;
if (chan[i].furnacePCM) {
if (dumpWrites) { // Sega PCM writes
DivSample* s=parent->getSample(chan[i].pcm.sample);
int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT));
if (actualLength>0xfeff) actualLength=0xfeff;
addWrite(0x10086+(i<<3),3+((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
addWrite(0x10084+(i<<3),(sampleOffSegaPCM[chan[i].pcm.sample])&0xff);
addWrite(0x10085+(i<<3),(sampleOffSegaPCM[chan[i].pcm.sample]>>8)&0xff);
addWrite(0x10006+(i<<3),MIN(255,((sampleOffSegaPCM[chan[i].pcm.sample]&0xffff)+actualLength-1)>>8));
if (loopStart<0 || loopStart>=actualLength) {
addWrite(0x10086+(i<<3),2+((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
} else {
int loopPos=(sampleOffSegaPCM[chan[i].pcm.sample]&0xffff)+loopStart+s->loopOffP;
addWrite(0x10004+(i<<3),loopPos&0xff);
addWrite(0x10005+(i<<3),(loopPos>>8)&0xff);
addWrite(0x10086+(i<<3),((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
}
DivSample* s=parent->getSample(chan[i].pcm.sample);
int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT));
if (actualLength>0xfeff) actualLength=0xfeff;
rWrite(0x86+(i<<3),3+((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
rWrite(0x84+(i<<3),(sampleOffSegaPCM[chan[i].pcm.sample])&0xff);
rWrite(0x85+(i<<3),(sampleOffSegaPCM[chan[i].pcm.sample]>>8)&0xff);
rWrite(6+(i<<3),MIN(255,((sampleOffSegaPCM[chan[i].pcm.sample]&0xffff)+actualLength-1)>>8));
if (loopStart<0 || loopStart>=actualLength) {
rWrite(0x86+(i<<3),2+((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
} else {
int loopPos=(sampleOffSegaPCM[chan[i].pcm.sample]&0xffff)+loopStart+sampleLoopOff[chan[i].pcm.sample];
rWrite(4+(i<<3),loopPos&0xff);
rWrite(5+(i<<3),(loopPos>>8)&0xff);
rWrite(0x86+(i<<3),((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
}
} else {
if (dumpWrites) { // Sega PCM writes
DivSample* s=parent->getSample(chan[i].pcm.sample);
int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT));
if (actualLength>65536) actualLength=65536;
addWrite(0x10086+(i<<3),3+((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
addWrite(0x10084+(i<<3),(sampleOffSegaPCM[chan[i].pcm.sample])&0xff);
addWrite(0x10085+(i<<3),(sampleOffSegaPCM[chan[i].pcm.sample]>>8)&0xff);
addWrite(0x10006+(i<<3),MIN(255,((sampleOffSegaPCM[chan[i].pcm.sample]&0xffff)+actualLength-1)>>8));
if (loopStart<0 || loopStart>=actualLength) {
addWrite(0x10086+(i<<3),2+((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
} else {
int loopPos=(sampleOffSegaPCM[chan[i].pcm.sample]&0xffff)+loopStart+s->loopOffP;
addWrite(0x10004+(i<<3),loopPos&0xff);
addWrite(0x10005+(i<<3),(loopPos>>8)&0xff);
addWrite(0x10086+(i<<3),((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
}
addWrite(0x10007+(i<<3),chan[i].pcm.freq);
DivSample* s=parent->getSample(chan[i].pcm.sample);
int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT));
if (actualLength>0xfeff) actualLength=0xfeff;
rWrite(0x86+(i<<3),3+((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
rWrite(0x84+(i<<3),(sampleOffSegaPCM[chan[i].pcm.sample])&0xff);
rWrite(0x85+(i<<3),(sampleOffSegaPCM[chan[i].pcm.sample]>>8)&0xff);
rWrite(6+(i<<3),MIN(255,((sampleOffSegaPCM[chan[i].pcm.sample]&0xffff)+actualLength-1)>>8));
if (loopStart<0 || loopStart>=actualLength) {
rWrite(0x86+(i<<3),2+((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
} else {
int loopPos=(sampleOffSegaPCM[chan[i].pcm.sample]&0xffff)+loopStart+sampleLoopOff[chan[i].pcm.sample];
rWrite(4+(i<<3),loopPos&0xff);
rWrite(5+(i<<3),(loopPos>>8)&0xff);
rWrite(0x86+(i<<3),((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
}
rWrite(7+(i<<3),chan[i].pcm.freq);
}
}
chan[i].keyOn=false;
@ -206,6 +170,7 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
void DivPlatformSegaPCM::muteChannel(int ch, bool mute) {
isMuted[ch]=mute;
pcm.mute(ch,mute);
}
int DivPlatformSegaPCM::dispatch(DivCommand c) {
@ -219,9 +184,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
if (c.value!=DIV_NOTE_NULL) chan[c.chan].pcm.sample=ins->amiga.getSample(c.value);
if (chan[c.chan].pcm.sample<0 || chan[c.chan].pcm.sample>=parent->song.sampleLen) {
chan[c.chan].pcm.sample=-1;
if (dumpWrites) {
addWrite(0x10086+(c.chan<<3),3);
}
rWrite(0x86+(c.chan<<3),3);
chan[c.chan].macroInit(NULL);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
@ -245,9 +208,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
chan[c.chan].pcm.sample=12*sampleBank+chan[c.chan].note%12;
if (chan[c.chan].pcm.sample>=parent->song.sampleLen) {
chan[c.chan].pcm.sample=-1;
if (dumpWrites) {
addWrite(0x10086+(c.chan<<3),3);
}
rWrite(0x86+(c.chan<<3),3);
break;
}
chan[c.chan].pcm.freq=MIN(255,(parent->getSample(chan[c.chan].pcm.sample)->rate*255)/31250);
@ -259,9 +220,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
}
case DIV_CMD_NOTE_OFF:
chan[c.chan].pcm.sample=-1;
if (dumpWrites) {
addWrite(0x10086+(c.chan<<3),3);
}
rWrite(0x86+(c.chan<<3),3);
chan[c.chan].keyOff=true;
chan[c.chan].keyOn=false;
chan[c.chan].active=false;
@ -288,10 +247,8 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
chan[c.chan].chVolL=c.value;
chan[c.chan].chVolR=c.value;
}
if (dumpWrites) {
addWrite(0x10002+(c.chan<<3),chan[c.chan].chVolL);
addWrite(0x10003+(c.chan<<3),chan[c.chan].chVolR);
}
rWrite(2+(c.chan<<3),chan[c.chan].chVolL);
rWrite(3+(c.chan<<3),chan[c.chan].chVolR);
break;
}
case DIV_CMD_GET_VOLUME: {
@ -314,10 +271,8 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
chan[c.chan].chVolL=c.value>>1;
chan[c.chan].chVolR=c.value2>>1;
}
if (dumpWrites) {
addWrite(0x10002+(c.chan<<3),chan[c.chan].chVolL);
addWrite(0x10003+(c.chan<<3),chan[c.chan].chVolR);
}
rWrite(2+(c.chan<<3),chan[c.chan].chVolL);
rWrite(3+(c.chan<<3),chan[c.chan].chVolR);
break;
}
case DIV_CMD_PITCH: {
@ -381,9 +336,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
break;
case DIV_CMD_SAMPLE_FREQ:
chan[c.chan].pcm.freq=c.value;
if (dumpWrites) {
addWrite(0x10007+(c.chan<<3),chan[c.chan].pcm.freq);
}
rWrite(7+(c.chan<<3),chan[c.chan].pcm.freq);
break;
default:
//printf("WARNING: unimplemented command %d\n",c.cmd);
@ -395,6 +348,10 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
void DivPlatformSegaPCM::forceIns() {
for (int i=0; i<16; i++) {
chan[i].insChanged=true;
rWrite(2+(i<<3),chan[i].chVolL);
rWrite(3+(i<<3),chan[i].chVolR);
rWrite(7+(i<<3),chan[i].pcm.freq);
}
}
@ -425,7 +382,7 @@ DivDispatchOscBuffer* DivPlatformSegaPCM::getOscBuffer(int ch) {
}
unsigned char* DivPlatformSegaPCM::getRegisterPool() {
return regPool;
return pcm.get_ram();
}
int DivPlatformSegaPCM::getRegisterPoolSize() {
@ -433,11 +390,29 @@ int DivPlatformSegaPCM::getRegisterPoolSize() {
}
void DivPlatformSegaPCM::poke(unsigned int addr, unsigned short val) {
//immWrite(addr,val);
rWrite(addr,val);
}
void DivPlatformSegaPCM::poke(std::vector<DivRegWrite>& wlist) {
//for (DivRegWrite& i: wlist) immWrite(i.addr,i.val);
for (DivRegWrite& i: wlist) rWrite(i.addr,i.val);
}
const void* DivPlatformSegaPCM::getSampleMem(int index) {
return index == 0 ? sampleMem : NULL;
}
size_t DivPlatformSegaPCM::getSampleMemCapacity(int index) {
return index == 0 ? 16777216 : 0;
}
size_t DivPlatformSegaPCM::getSampleMemUsage(int index) {
return index == 0 ? sampleMemLen : 0;
}
bool DivPlatformSegaPCM::isSampleLoaded(int index, int sample) {
if (index!=0) return false;
if (sample<0 || sample>255) return false;
return sampleLoaded[sample];
}
void DivPlatformSegaPCM::reset() {
@ -457,17 +432,20 @@ void DivPlatformSegaPCM::reset() {
sampleBank=0;
delay=0;
if (dumpWrites) {
for (int i=0; i<16; i++) {
addWrite(0x10086+(i<<3),3);
addWrite(0x10002+(i<<3),0x7f);
addWrite(0x10003+(i<<3),0x7f);
}
pcm.device_start();
for (int i=0; i<16; i++) {
rWrite(0x86+(i<<3),3);
rWrite(2+(i<<3),0x7f);
rWrite(3+(i<<3),0x7f);
}
}
void DivPlatformSegaPCM::renderSamples(int sysID) {
size_t memPos=0;
memset(sampleMem,0,16777216);
memset(sampleLoaded,0,256*sizeof(bool));
for (int i=0; i<parent->song.sampleLen; i++) {
DivSample* sample=parent->getSample(i);
@ -477,6 +455,7 @@ void DivPlatformSegaPCM::reset() {
memPos=(memPos+0xffff)&0xff0000;
}
logV("- sample %d will be at %x with length %x",i,memPos,alignedSize);
sampleLoaded[i]=true;
if (memPos>=16777216) break;
sampleOffSegaPCM[i]=memPos;
unsigned int readPos=0;
@ -484,20 +463,21 @@ void DivPlatformSegaPCM::reset() {
if (readPos>=(unsigned int)sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)) {
if (sample->isLoopable()) {
readPos=sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
memPos++;
sampleMem[memPos++]=((unsigned char)sample->data8[readPos]+0x80);
} else {
memPos++;
sampleMem[memPos++]=0x80;
}
} else {
memPos++;
sampleMem[memPos++]=((unsigned char)sample->data8[readPos]+0x80);
}
readPos++;
if (memPos>=16777216) break;
}
sample->loopOffP=readPos-sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
sampleLoopOff[i]=readPos-sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
if (memPos>=16777216) break;
}
}
sampleMemLen=memPos;
}
void DivPlatformSegaPCM::setFlags(const DivConfig& flags) {
chipClock=8000000.0;
@ -520,6 +500,11 @@ int DivPlatformSegaPCM::init(DivEngine* p, int channels, int sugRate, const DivC
isMuted[i]=false;
oscBuf[i]=new DivDispatchOscBuffer;
}
sampleMem=new unsigned char[16777216];
pcm.set_bank(segapcm_device::BANK_12M|segapcm_device::BANK_MASKF8);
pcm.set_read([this](unsigned int addr) -> unsigned char {
return sampleMem[addr&0xffffff];
});
setFlags(flags);
reset();
@ -530,6 +515,7 @@ void DivPlatformSegaPCM::quit() {
for (int i=0; i<16; i++) {
delete oscBuf[i];
}
delete sampleMem;
}
DivPlatformSegaPCM::~DivPlatformSegaPCM() {

View File

@ -53,6 +53,8 @@ class DivPlatformSegaPCM: public DivDispatch {
};
Channel chan[16];
DivDispatchOscBuffer* oscBuf[16];
unsigned char* sampleMem;
size_t sampleMemLen;
struct QueuedWrite {
unsigned short addr;
unsigned char val;
@ -74,6 +76,8 @@ class DivPlatformSegaPCM: public DivDispatch {
short pendingWrites[256];
unsigned int sampleOffSegaPCM[256];
unsigned int sampleLoopOff[256];
bool sampleLoaded[256];
friend void putDispatchChip(void*,int);
friend void putDispatchChan(void*,int,int);
@ -97,6 +101,10 @@ class DivPlatformSegaPCM: public DivDispatch {
int getOutputCount();
void poke(unsigned int addr, unsigned short val);
void poke(std::vector<DivRegWrite>& wlist);
const void* getSampleMem(int index=0);
size_t getSampleMemCapacity(int index=0);
size_t getSampleMemUsage(int index=0);
bool isSampleLoaded(int index, int sample);
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
void quit();
~DivPlatformSegaPCM();

View File

@ -16,6 +16,7 @@ segapcm_device::segapcm_device()
: m_bankshift(12)
, m_bankmask(0x70)
{
memset(m_muted,0,16*sizeof(bool));
}
@ -94,8 +95,13 @@ void segapcm_device::sound_stream_update(int* outputs)
v = read_byte(offset + (addr >> 8)) - 0x80;
/* apply panning and advance */
lastOut[ch][0]=v * (regs[2] & 0x7f);
lastOut[ch][1]=v * (regs[3] & 0x7f);
if (m_muted[ch]) {
lastOut[ch][0]=0;
lastOut[ch][1]=0;
} else {
lastOut[ch][0]=v * (regs[2] & 0x7f);
lastOut[ch][1]=v * (regs[3] & 0x7f);
}
outputs[0]+=lastOut[ch][0];
outputs[1]+=lastOut[ch][1];
addr = (addr + regs[7]) & 0xffffff;
@ -123,3 +129,11 @@ uint8_t segapcm_device::read(unsigned int offset)
{
return m_ram[offset & 0x07ff];
}
uint8_t* segapcm_device::get_ram() {
return m_ram;
}
void segapcm_device::mute(int ch, bool doMute) {
m_muted[ch&15]=doMute;
}

View File

@ -7,6 +7,7 @@
#ifndef MAMESOUND_SEGAPCM_H
#define MAMESOUND_SEGAPCM_H
#include <stdint.h>
#include <functional>
//**************************************************************************
@ -22,7 +23,7 @@ public:
static constexpr int BANK_MASKF = 0xf0 << 16;
static constexpr int BANK_MASKF8 = 0xf8 << 16;
short lastOut[16][2];
short lastOut[16][2];
segapcm_device();
@ -32,6 +33,8 @@ public:
void write(unsigned int offset, uint8_t data);
uint8_t read(unsigned int offset);
uint8_t* get_ram();
void mute(int ch, bool doMute);
// device-level overrides
void device_start();
@ -42,6 +45,7 @@ public:
private:
uint8_t m_ram[0x800];
uint8_t m_low[16];
bool m_muted[16];
int m_bankshift;
int m_bankmask;
std::function<unsigned char(unsigned int)> read_byte;

View File

@ -95,8 +95,7 @@ struct DivSampleHistory {
struct DivSample {
String name;
// TODO: get rid of loopOffP
int rate, centerRate, loopStart, loopEnd, loopOffP;
int rate, centerRate, loopStart, loopEnd;
// valid values are:
// - 0: ZX Spectrum overlay drum (1-bit)
// - 1: 1-bit NES DPCM (1-bit)
@ -306,7 +305,6 @@ struct DivSample {
centerRate(8363),
loopStart(-1),
loopEnd(-1),
loopOffP(0),
depth(DIV_SAMPLE_DEPTH_16BIT),
loop(false),
brrEmphasis(true),

View File

@ -1085,7 +1085,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
DivDispatch* writeADPCM_OPNA[2]={NULL,NULL};
DivDispatch* writeADPCM_OPNB[2]={NULL,NULL};
DivDispatch* writeADPCM_Y8950[2]={NULL,NULL};
int writeSegaPCM=0;
DivDispatch* writeSegaPCM[2]={NULL,NULL};
DivDispatch* writeX1010[2]={NULL,NULL};
DivDispatch* writeQSound[2]={NULL,NULL};
DivDispatch* writeES5506[2]={NULL,NULL};
@ -1177,12 +1177,12 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
hasSegaPCM=4000000;
CHIP_VOL(4,0.67);
willExport[i]=true;
writeSegaPCM=1;
writeSegaPCM[0]=disCont[i].dispatch;
} else if (!(hasSegaPCM&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(4,0.67);
willExport[i]=true;
writeSegaPCM=2;
writeSegaPCM[1]=disCont[i].dispatch;
hasSegaPCM|=0x40000000;
howManyChips++;
}
@ -1843,53 +1843,17 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
}
}
if (writeSegaPCM>0) {
unsigned char* pcmMem=new unsigned char[16777216];
size_t memPos=0;
for (int i=0; i<song.sampleLen; i++) {
DivSample* sample=song.sample[i];
unsigned int alignedSize=(sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)+0xff)&(~0xff);
if (alignedSize>65536) alignedSize=65536;
if ((memPos&0xff0000)!=((memPos+alignedSize)&0xff0000)) {
memPos=(memPos+0xffff)&0xff0000;
}
logV("- sample %d will be at %x with length %x",i,memPos,alignedSize);
if (memPos>=16777216) break;
sampleOffSegaPCM[i]=memPos;
unsigned int readPos=0;
for (unsigned int j=0; j<alignedSize; j++) {
if (readPos>=(unsigned int)sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)) {
if (sample->isLoopable()) {
readPos=sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
pcmMem[memPos++]=((unsigned char)sample->data8[readPos]+0x80);
} else {
pcmMem[memPos++]=0x80;
}
} else {
pcmMem[memPos++]=((unsigned char)sample->data8[readPos]+0x80);
}
readPos++;
if (memPos>=16777216) break;
}
sample->loopOffP=readPos-sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
if (memPos>=16777216) break;
}
for (unsigned char i=0; i<writeSegaPCM; i++) {
for (int i=0; i<2; i++) {
// SegaPCM
if (writeSegaPCM[i]!=NULL && writeSegaPCM[i]->getSampleMemUsage(0)>0) {
w->writeC(0x67);
w->writeC(0x66);
w->writeC(0x80);
w->writeI((memPos+8)|(i*0x80000000));
w->writeI(memPos);
w->writeC(0x81);
w->writeI((writeSegaPCM[i]->getSampleMemUsage(0)+8)|(i*0x80000000));
w->writeI(writeSegaPCM[i]->getSampleMemCapacity(0));
w->writeI(0);
w->write(pcmMem,memPos);
w->write(writeSegaPCM[i]->getSampleMem(0),writeSegaPCM[i]->getSampleMemUsage(0));
}
delete[] pcmMem;
}
for (int i=0; i<2; i++) {
// ADPCM (OPNA)
if (writeADPCM_OPNA[i]!=NULL && writeADPCM_OPNA[i]->getSampleMemUsage(0)>0) {
w->writeC(0x67);

View File

@ -149,6 +149,7 @@ const char* aboutLine[]={
"MAME MSM6258 core by Barry Rodewald",
"MAME YMZ280B core by Aaron Giles",
"MAME GA20 core by Acho A. Tang and R. Belmont",
"MAME SegaPCM core by Hiromitsu Shioya and Olivier Galibert",
"SAASound by Dave Hooper and Simon Owen",
"SameBoy by Lior Halphon",
"Mednafen PCE, WonderSwan, T6W28 and Virtual Boy audio cores",

View File

@ -183,7 +183,6 @@ void FurnaceGUI::drawDebug() {
ImGui::Text("centerRate: %d",sample->centerRate);
ImGui::Text("loopStart: %d",sample->loopStart);
ImGui::Text("loopEnd: %d", sample->loopEnd);
ImGui::Text("loopOffP: %d",sample->loopOffP);
ImGui::Text(sample->loop?"loop: Enabled":"loop: Disabled");
if (sampleLoopModes[sample->loopMode]!=NULL) {
ImGui::Text("loopMode: %d (%s)",(unsigned char)sample->loopMode,sampleLoopModes[sample->loopMode]);

View File

@ -185,6 +185,7 @@ TAParamResult pVersion(String) {
printf("- MAME MSM6258 core by Barry Rodewald (BSD 3-clause)\n");
printf("- MAME YMZ280B core by Aaron Giles (BSD 3-clause)\n");
printf("- MAME GA20 core by Acho A. Tang and R. Belmont (BSD 3-clause)\n");
printf("- MAME SegaPCM core by Hiromitsu Shioya and Olivier Galibert (BSD 3-clause)\n");
printf("- QSound core by superctr (BSD 3-clause)\n");
printf("- VICE VIC-20 by Rami Rasanen and viznut (GPLv2)\n");
printf("- VERA core by Frank van den Hoef (BSD 2-clause)\n");