Add OPL4/MultiPCM 12-bit PCM support

This commit is contained in:
cam900 2024-08-16 20:45:40 +09:00
parent 2c417811b3
commit 16ca40e0d2
6 changed files with 54 additions and 7 deletions

View file

@ -587,6 +587,7 @@ size | description
| - 11: 8-bit μ-law PCM
| - 12: C219 PCM
| - 13: IMA ADPCM
| - 14: 12-bit PCM (MultiPCM)
| - 16: 16-bit PCM
1 | loop direction (>=123) or reserved
| - 0: forward

View file

@ -3197,6 +3197,9 @@ void DivPlatformOPL::renderSamples(int sysID) {
case DIV_SAMPLE_DEPTH_8BIT:
length=MIN(65535,s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT));
break;
case DIV_SAMPLE_DEPTH_12BIT:
length=MIN(98303,s->getLoopEndPosition(DIV_SAMPLE_DEPTH_12BIT));
break;
case DIV_SAMPLE_DEPTH_16BIT:
length=MIN(131070,s->getLoopEndPosition(DIV_SAMPLE_DEPTH_16BIT));
break;
@ -3239,7 +3242,9 @@ void DivPlatformOPL::renderSamples(int sysID) {
case DIV_SAMPLE_DEPTH_8BIT:
bitDepth=0;
break;
// TODO: 12 bit PCM
case DIV_SAMPLE_DEPTH_12BIT:
bitDepth=1;
break;
case DIV_SAMPLE_DEPTH_16BIT:
bitDepth=2;
break;

View file

@ -285,6 +285,9 @@ int DivSample::getSampleOffset(int offset, int length, DivSampleDepth depth) {
case DIV_SAMPLE_DEPTH_IMA_ADPCM:
off=(offset+1)/2;
break;
case DIV_SAMPLE_DEPTH_12BIT:
off=((offset*3)+1)/2;
break;
case DIV_SAMPLE_DEPTH_16BIT:
off=offset*2;
break;
@ -348,6 +351,10 @@ int DivSample::getSampleOffset(int offset, int length, DivSampleDepth depth) {
off=(offset+1)/2;
len=(length+1)/2;
break;
case DIV_SAMPLE_DEPTH_12BIT:
off=((offset*3)+1)/2;
len=((length*3)+1)/2;
break;
case DIV_SAMPLE_DEPTH_16BIT:
off=offset*2;
len=length*2;
@ -409,6 +416,9 @@ int DivSample::getEndPosition(DivSampleDepth depth) {
case DIV_SAMPLE_DEPTH_IMA_ADPCM:
off=lengthIMA;
break;
case DIV_SAMPLE_DEPTH_12BIT:
off=length12;
break;
case DIV_SAMPLE_DEPTH_16BIT:
off=length16;
break;
@ -606,6 +616,12 @@ bool DivSample::initInternal(DivSampleDepth d, int count) {
dataIMA=new unsigned char[lengthIMA];
memset(dataIMA,0,lengthIMA);
break;
case DIV_SAMPLE_DEPTH_12BIT: // 12-bit PCM (MultiPCM)
if (data12!=NULL) delete[] data12;
length12=((count*3)+1)/2;
data12=new unsigned char[length12];
memset(data12,0,length12);
break;
case DIV_SAMPLE_DEPTH_16BIT: // 16-bit
if (data16!=NULL) delete[] data16;
length16=count*2;
@ -1293,6 +1309,14 @@ void DivSample::render(unsigned int formatMask) {
case DIV_SAMPLE_DEPTH_IMA_ADPCM: // IMA ADPCM
if (adpcm_decode_block(data16,dataIMA,lengthIMA,samples)==0) logE("oh crap!");
break;
case DIV_SAMPLE_DEPTH_12BIT: // 12-bit PCM (MultiPCM)
for (unsigned int i=0,j=0; i<samples; i+=2,j+=3) {
data16[i+0]=(data12[j+0]<<8)|(data12[j+1]&0xf0);
if (i+1<samples) {
data16[i+1]=(data12[j+2]<<8)|((data12[j+1]<<4)&0xf0);
}
}
break;
default:
return;
}
@ -1482,6 +1506,15 @@ void DivSample::render(unsigned int formatMask) {
adpcm_free_context(codec);
}
}
if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_12BIT)) { // 12-bit PCM (MultiPCM)
if (!initInternal(DIV_SAMPLE_DEPTH_12BIT,samples)) return;
for (unsigned int i=0,j=0; i<samples; i+=2,j+=3) {
data12[j+0]=data16[i+0]>>8;
data12[j+1]=((data16[i+0]>>4)&0xf)|(i+1<samples?(data16[i+1]>>4)&0xf:0);
if (i+1<samples)
data12[j+2]=data16[i+1]>>8;
}
}
}
void* DivSample::getCurBuf() {
@ -1512,6 +1545,8 @@ void* DivSample::getCurBuf() {
return dataC219;
case DIV_SAMPLE_DEPTH_IMA_ADPCM:
return dataIMA;
case DIV_SAMPLE_DEPTH_12BIT:
return data12;
case DIV_SAMPLE_DEPTH_16BIT:
return data16;
default:
@ -1548,6 +1583,8 @@ unsigned int DivSample::getCurBufLen() {
return lengthC219;
case DIV_SAMPLE_DEPTH_IMA_ADPCM:
return lengthIMA;
case DIV_SAMPLE_DEPTH_12BIT:
return length12;
case DIV_SAMPLE_DEPTH_16BIT:
return length16;
default:
@ -1662,4 +1699,5 @@ DivSample::~DivSample() {
if (dataMuLaw) delete[] dataMuLaw;
if (dataC219) delete[] dataC219;
if (dataIMA) delete[] dataIMA;
if (data12) delete[] data12;
}

View file

@ -47,6 +47,7 @@ enum DivSampleDepth: unsigned char {
DIV_SAMPLE_DEPTH_MULAW=11,
DIV_SAMPLE_DEPTH_C219=12,
DIV_SAMPLE_DEPTH_IMA_ADPCM=13,
DIV_SAMPLE_DEPTH_12BIT=14,
DIV_SAMPLE_DEPTH_16BIT=16,
DIV_SAMPLE_DEPTH_MAX // boundary for sample depth
};
@ -118,6 +119,7 @@ struct DivSample {
// - 11: 8-bit µ-law PCM
// - 12: C219 "µ-law" PCM
// - 13: IMA ADPCM
// - 14: 12-bit PCM (MultiPCM)
// - 16: 16-bit PCM
DivSampleDepth depth;
bool loop, brrEmphasis, brrNoFilter, dither;
@ -144,8 +146,9 @@ struct DivSample {
unsigned char* dataMuLaw; // 11
unsigned char* dataC219; // 12
unsigned char* dataIMA; // 13
unsigned char* data12; // 14
unsigned int length8, length16, length1, lengthDPCM, lengthZ, lengthQSoundA, lengthA, lengthB, lengthK, lengthBRR, lengthVOX, lengthMuLaw, lengthC219, lengthIMA;
unsigned int length8, length16, length1, lengthDPCM, lengthZ, lengthQSoundA, lengthA, lengthB, lengthK, lengthBRR, lengthVOX, lengthMuLaw, lengthC219, lengthIMA, length12;
unsigned int samples;
@ -356,6 +359,7 @@ struct DivSample {
dataMuLaw(NULL),
dataC219(NULL),
dataIMA(NULL),
data12(NULL),
length8(0),
length16(0),
length1(0),
@ -370,6 +374,7 @@ struct DivSample {
lengthMuLaw(0),
lengthC219(0),
lengthIMA(0),
length12(0),
samples(0) {
for (int i=0; i<DIV_MAX_CHIPS; i++) {
for (int j=0; j<DIV_MAX_SAMPLE_TYPE; j++) {

View file

@ -1635,9 +1635,8 @@ void DivEngine::registerSystems() {
);
// to Grauw: feel free to change this to 24 during development of OPL4's PCM part.
// TODO: add 12-bit sample formats
sysDefs[DIV_SYSTEM_OPL4]=new DivSysDef(
_("Yamaha YMF278B (OPL4)"), NULL, 0xae, 0, 42, true, true, 0x151, false, (1U<<DIV_SAMPLE_DEPTH_8BIT)|(1U<<DIV_SAMPLE_DEPTH_16BIT), 0, 0,
_("Yamaha YMF278B (OPL4)"), NULL, 0xae, 0, 42, true, true, 0x151, false, (1U<<DIV_SAMPLE_DEPTH_8BIT)|(1U<<DIV_SAMPLE_DEPTH_12BIT)|(1U<<DIV_SAMPLE_DEPTH_16BIT), 0, 0,
_("like OPL3, but this time it also has a 24-channel version of MultiPCM."),
{_("4OP 1"), _("FM 2"), _("4OP 3"), _("FM 4"), _("4OP 5"), _("FM 6"), _("4OP 7"), _("FM 8"), _("4OP 9"), _("FM 10"), _("4OP 11"), _("FM 12"), _("FM 13"), _("FM 14"), _("FM 15"), _("FM 16"), _("FM 17"), _("FM 18"), _("PCM 1"), _("PCM 2"), _("PCM 3"), _("PCM 4"), _("PCM 5"), _("PCM 6"), _("PCM 7"), _("PCM 8"), _("PCM 9"), _("PCM 10"), _("PCM 11"), _("PCM 12"), _("PCM 13"), _("PCM 14"), _("PCM 15"), _("PCM 16"), _("PCM 17"), _("PCM 18"), _("PCM 19"), _("PCM 20"), _("PCM 21"), _("PCM 22"), _("PCM 23"), _("PCM 24")},
{"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "F16", "F17", "F18", "P1", "P2", "P3", "P4", "P5", "P6", "P7", "P8", "P9", "P10", "P11", "P12", "P13", "P14", "P15", "P16", "P17", "P18", "P19", "P20", "P21", "P22", "P23", "P24"},
@ -1648,9 +1647,8 @@ void DivEngine::registerSystems() {
fmOPL4PostEffectHandlerMap
);
// TODO: same here
sysDefs[DIV_SYSTEM_OPL4_DRUMS]=new DivSysDef(
_("Yamaha YMF278B (OPL4) with drums"), NULL, 0xaf, 0, 44, true, true, 0x151, false, (1U<<DIV_SAMPLE_DEPTH_8BIT)|(1U<<DIV_SAMPLE_DEPTH_16BIT), 0, 0,
_("Yamaha YMF278B (OPL4) with drums"), NULL, 0xaf, 0, 44, true, true, 0x151, false, (1U<<DIV_SAMPLE_DEPTH_8BIT)|(1U<<DIV_SAMPLE_DEPTH_12BIT)|(1U<<DIV_SAMPLE_DEPTH_16BIT), 0, 0,
_("the OPL4 but with drums mode turned on."),
{_("4OP 1"), _("FM 2"), _("4OP 3"), _("FM 4"), _("4OP 5"), _("FM 6"), _("4OP 7"), _("FM 8"), _("4OP 9"), _("FM 10"), _("4OP 11"), _("FM 12"), _("FM 13"), _("FM 14"), _("FM 15"), _("Kick/FM 16"), _("Snare"), _("Tom"), _("Top"), _("HiHat"), _("PCM 1"), _("PCM 2"), _("PCM 3"), _("PCM 4"), _("PCM 5"), _("PCM 6"), _("PCM 7"), _("PCM 8"), _("PCM 9"), _("PCM 10"), _("PCM 11"), _("PCM 12"), _("PCM 13"), _("PCM 14"), _("PCM 15"), _("PCM 16"), _("PCM 17"), _("PCM 18"), _("PCM 19"), _("PCM 20"), _("PCM 21"), _("PCM 22"), _("PCM 23"), _("PCM 24")},
{"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "BD", "SD", "TM", "TP", "HH", "P1", "P2", "P3", "P4", "P5", "P6", "P7", "P8", "P9", "P10", "P11", "P12", "P13", "P14", "P15", "P16", "P17", "P18", "P19", "P20", "P21", "P22", "P23", "P24"},

View file

@ -208,7 +208,7 @@ const char* sampleDepths[DIV_SAMPLE_DEPTH_MAX]={
"8-bit µ-law PCM",
"C219 PCM",
"IMA ADPCM",
NULL,
"12-bit PCM",
NULL,
"16-bit PCM"
};