C219: new sample format (work in progress)

This commit is contained in:
tildearrow 2023-08-28 20:31:22 -05:00
parent 9cb239438e
commit a5f351c232
8 changed files with 146 additions and 49 deletions

61
src/engine/bsr.h Normal file
View File

@ -0,0 +1,61 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2023 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.
*/
#if defined( _MSC_VER )
#include <intrin.h>
static inline int bsr(unsigned short v) {
unsigned long idx;
if (_BitScanReverse(&idx,(unsigned long)v)) {
return idx;
}
else {
return -1;
}
}
#elif defined( __GNUC__ )
static inline int bsr(unsigned short v)
{
if (v) {
return 32 - __builtin_clz(v);
}
else{
return -1;
}
}
#else
static inline int bsr(unsigned short v)
{
unsigned short mask = 0x8000;
for (int i = 15; i >= 0; --i) {
if (v&mask)
return (int)i;
mask>>=1;
}
return -1;
}
#endif

View File

@ -395,6 +395,7 @@ DivSample* DivEngine::sampleFromFileRaw(const char* path, DivSampleDepth depth,
break;
case DIV_SAMPLE_DEPTH_8BIT:
case DIV_SAMPLE_DEPTH_MULAW:
case DIV_SAMPLE_DEPTH_C219:
samples=lenDivided;
break;
case DIV_SAMPLE_DEPTH_BRR:

View File

@ -575,13 +575,12 @@ void DivPlatformC140::renderSamples(int sysID) {
length=getSampleMemCapacity()-memPos;
logW("out of C219 memory for sample %d!",i);
}
if (s->depth==DIV_SAMPLE_DEPTH_MULAW) {
if (s->depth==DIV_SAMPLE_DEPTH_C219) {
for (unsigned int i=0; i<length; i++) {
if (i>=s->lengthMuLaw) {
if (i>=s->lengthC219) {
sampleMem[i+memPos]=0;
} else {
unsigned char x=s->dataMuLaw[i]^0xff;
sampleMem[i+memPos]=x;
sampleMem[i+memPos]=s->dataC219[i];
}
}
} else {

View File

@ -19,6 +19,7 @@
#include "lynx.h"
#include "../engine.h"
#include "../bsr.h"
#include <math.h>
#define rWrite(a,v) {if (!skipRegisterWrites) {mikey->write(a,v); if (dumpWrites) {addWrite(a,v);}}}
@ -36,48 +37,6 @@
#define CHIP_DIVIDER 64
#define CHIP_FREQBASE 16000000
#if defined( _MSC_VER )
#include <intrin.h>
static int bsr(uint16_t v) {
unsigned long idx;
if (_BitScanReverse(&idx,(unsigned long)v)) {
return idx;
}
else {
return -1;
}
}
#elif defined( __GNUC__ )
static int bsr(uint16_t v)
{
if (v) {
return 32 - __builtin_clz(v);
}
else{
return -1;
}
}
#else
static int bsr(uint16_t v)
{
uint16_t mask = 0x8000;
for (int i = 15; i >= 0; --i) {
if (v&mask)
return (int)i;
mask>>=1;
}
return -1;
}
#endif
static int32_t clamp(int32_t v, int32_t lo, int32_t hi)
{
return v<lo?lo:(v>hi?hi:v);

View File

@ -26,6 +26,7 @@
#include "sfWrapper.h"
#endif
#include "filter.h"
#include "bsr.h"
extern "C" {
#include "../../extern/adpcm/bs_codec.h"
@ -272,6 +273,9 @@ int DivSample::getSampleOffset(int offset, int length, DivSampleDepth depth) {
case DIV_SAMPLE_DEPTH_MULAW:
off=offset;
break;
case DIV_SAMPLE_DEPTH_C219:
off=offset;
break;
case DIV_SAMPLE_DEPTH_16BIT:
off=offset*2;
break;
@ -323,6 +327,10 @@ int DivSample::getSampleOffset(int offset, int length, DivSampleDepth depth) {
off=offset;
len=length;
break;
case DIV_SAMPLE_DEPTH_C219:
off=offset;
len=length;
break;
case DIV_SAMPLE_DEPTH_16BIT:
off=offset*2;
len=length*2;
@ -375,6 +383,9 @@ int DivSample::getEndPosition(DivSampleDepth depth) {
case DIV_SAMPLE_DEPTH_MULAW:
off=lengthMuLaw;
break;
case DIV_SAMPLE_DEPTH_C219:
off=lengthC219;
break;
case DIV_SAMPLE_DEPTH_16BIT:
off=length16;
break;
@ -554,6 +565,12 @@ bool DivSample::initInternal(DivSampleDepth d, int count) {
dataMuLaw=new unsigned char[(count+4095)&(~0xfff)];
memset(dataMuLaw,0,(count+4095)&(~0xfff));
break;
case DIV_SAMPLE_DEPTH_C219: // 8-bit C219 "μ-law"
if (dataC219!=NULL) delete[] dataC219;
lengthC219=count;
dataC219=new unsigned char[(count+4095)&(~0xfff)];
memset(dataC219,0,(count+4095)&(~0xfff));
break;
case DIV_SAMPLE_DEPTH_16BIT: // 16-bit
if (data16!=NULL) delete[] data16;
length16=count*2;
@ -1133,6 +1150,33 @@ union IntFloat {
float f;
};
const short c219Table[256]={
0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 480,
512, 576, 640, 704, 768, 832, 896, 960, 1024, 1152, 1280, 1408, 1536, 1664, 1792, 1920,
2048, 2176, 2304, 2432, 2560, 2688, 2816, 2944, 3072, 3200, 3328, 3456, 3584, 3712, 3840, 3968,
4096, 4352, 4608, 4864, 5120, 5376, 5632, 5888, 6144, 6400, 6656, 6912, 7168, 7424, 7680, 7936,
8192, 8448, 8704, 8960, 9216, 9472, 9728, 9984, 10240, 10496, 10752, 11008, 11264, 11520, 11776, 12032,
12288, 12544, 12800, 13056, 13312, 13568, 13824, 14080, 14336, 14592, 14848, 15104, 15360, 15616, 15872, 16128,
16384, 16640, 16896, 17152, 17408, 17920, 18432, 18944, 19456, 19968, 20480, 20992, 21504, 22016, 22528, 23040,
23552, 24064, 24576, 25088, 25600, 26112, 26624, 27136, 27648, 28160, 28672, 29184, 29696, 30208, 30720, 31232,
-32, -64, -96, -128, -160, -192, -224, -256, -288, -320, -352, -384, -416, -448, -480, -512,
-544, -608, -672, -736, -800, -864, -928, -992, -1056, -1184, -1312, -1440, -1568, -1696, -1824, -1952,
-2080, -2208, -2336, -2464, -2592, -2720, -2848, -2976, -3104, -3232, -3360, -3488, -3616, -3744, -3872, -4000,
-4128, -4384, -4640, -4896, -5152, -5408, -5664, -5920, -6176, -6432, -6688, -6944, -7200, -7456, -7712, -7968,
-8224, -8480, -8736, -8992, -9248, -9504, -9760, -10016, -10272, -10528, -10784, -11040, -11296, -11552, -11808, -12064,
-12320, -12576, -12832, -13088, -13344, -13600, -13856, -14112, -14368, -14624, -14880, -15136, -15392, -15648, -15904, -16160,
-16416, -16672, -16928, -17184, -17440, -17952, -18464, -18976, -19488, -20000, -20512, -21024, -21536, -22048, -22560, -23072,
-23584, -24096, -24608, -25120, -25632, -26144, -26656, -27168, -27680, -28192, -28704, -29216, -29728, -30240, -30752, -31264
};
unsigned char c219HighBitPos[16]={
0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 24, 24, 48, 48, 48, 48
};
unsigned char c219ShiftToVal[16]={
5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 7, 8, 8, 8, 8
};
void DivSample::render(unsigned int formatMask) {
// step 1: convert to 16-bit if needed
if (depth!=DIV_SAMPLE_DEPTH_16BIT) {
@ -1184,6 +1228,12 @@ void DivSample::render(unsigned int formatMask) {
data16[i]=(short)(s.f*128.0f);
}
break;
case DIV_SAMPLE_DEPTH_C219: // 8-bit C219 "μ-law" PCM
for (unsigned int i=0; i<samples; i++) {
data16[i]=c219Table[dataC219[i]&0x7f];
if (dataC219[i]&0x80) data16[i]=-data16[i];
}
break;
default:
return;
}
@ -1273,6 +1323,23 @@ void DivSample::render(unsigned int formatMask) {
dataMuLaw[i]=(((data16[i]<0)?0x80:0)|(s.i&0x03f80000)>>19)^0xff;
}
}
if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_C219)) { // C219
if (!initInternal(DIV_SAMPLE_DEPTH_C219,samples)) return;
for (unsigned int i=0; i<samples; i++) {
short s=data16[i];
unsigned char x=0;
if (s>0) {
if (s>17152) { // 100+
x=((s-17152)>>9)+100;
} else {
int b=bsr(s)&15;
x=(s>>c219ShiftToVal[b])+c219HighBitPos[b];
}
} else if (s<0) {
}
dataC219[i]=x;
}
}
}
void* DivSample::getCurBuf() {
@ -1297,6 +1364,8 @@ void* DivSample::getCurBuf() {
return dataVOX;
case DIV_SAMPLE_DEPTH_MULAW:
return dataMuLaw;
case DIV_SAMPLE_DEPTH_C219:
return dataC219;
case DIV_SAMPLE_DEPTH_16BIT:
return data16;
default:
@ -1327,6 +1396,8 @@ unsigned int DivSample::getCurBufLen() {
return lengthVOX;
case DIV_SAMPLE_DEPTH_MULAW:
return lengthMuLaw;
case DIV_SAMPLE_DEPTH_C219:
return lengthC219;
case DIV_SAMPLE_DEPTH_16BIT:
return length16;
default:
@ -1437,4 +1508,5 @@ DivSample::~DivSample() {
if (dataBRR) delete[] dataBRR;
if (dataVOX) delete[] dataVOX;
if (dataMuLaw) delete[] dataMuLaw;
if (dataC219) delete[] dataC219;
}

View File

@ -44,6 +44,7 @@ enum DivSampleDepth: unsigned char {
DIV_SAMPLE_DEPTH_BRR=9,
DIV_SAMPLE_DEPTH_VOX=10,
DIV_SAMPLE_DEPTH_MULAW=11,
DIV_SAMPLE_DEPTH_C219=12,
DIV_SAMPLE_DEPTH_16BIT=16,
DIV_SAMPLE_DEPTH_MAX // boundary for sample depth
};
@ -110,6 +111,7 @@ struct DivSample {
// - 9: BRR (SNES)
// - 10: VOX ADPCM
// - 11: 8-bit µ-law PCM
// - 12: C219 "µ-law" PCM
// - 16: 16-bit PCM
DivSampleDepth depth;
bool loop, brrEmphasis, dither;
@ -133,8 +135,9 @@ struct DivSample {
unsigned char* dataBRR; // 9
unsigned char* dataVOX; // 10
unsigned char* dataMuLaw; // 11
unsigned char* dataC219; // 12
unsigned int length8, length16, length1, lengthDPCM, lengthZ, lengthQSoundA, lengthA, lengthB, lengthBRR, lengthVOX, lengthMuLaw;
unsigned int length8, length16, length1, lengthDPCM, lengthZ, lengthQSoundA, lengthA, lengthB, lengthBRR, lengthVOX, lengthMuLaw, lengthC219;
unsigned int samples;
@ -341,6 +344,7 @@ struct DivSample {
dataBRR(NULL),
dataVOX(NULL),
dataMuLaw(NULL),
dataC219(NULL),
length8(0),
length16(0),
length1(0),
@ -352,6 +356,7 @@ struct DivSample {
lengthBRR(0),
lengthVOX(0),
lengthMuLaw(0),
lengthC219(0),
samples(0) {
for (int i=0; i<DIV_MAX_CHIPS; i++) {
for (int j=0; j<DIV_MAX_SAMPLE_TYPE; j++) {

View File

@ -1888,7 +1888,7 @@ void DivEngine::registerSystems() {
);
sysDefs[DIV_SYSTEM_C219]=new DivSysDef(
"Namco C219", NULL, 0xcf, 0, 16, false, true, 0x161, false, (1U<<DIV_SAMPLE_DEPTH_MULAW)|(1U<<DIV_SAMPLE_DEPTH_8BIT),
"Namco C219", NULL, 0xcf, 0, 16, false, true, 0x161, false, (1U<<DIV_SAMPLE_DEPTH_C219)|(1U<<DIV_SAMPLE_DEPTH_8BIT),
"Namco's PCM chip used in their NA1/2 hardware.",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12", "Channel 13", "Channel 14", "Channel 15", "Channel 16"},
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16"},

View File

@ -197,7 +197,7 @@ const char* sampleDepths[DIV_SAMPLE_DEPTH_MAX]={
"BRR",
"VOX",
"8-bit µ-law PCM",
NULL,
"C219 PCM",
NULL,
NULL,
NULL,